core-maugli 1.2.67 → 1.2.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/astro.config.mjs CHANGED
@@ -37,7 +37,7 @@ export const pwaOptions = {
37
37
  workbox: {
38
38
  navigateFallback: '/index.html',
39
39
  cleanupOutdatedCaches: true,
40
- navigateFallbackDenylist: [/^\/api\//],
40
+ navigateFallbackDenylist: [/^\/api\//, /^\/sw\.js$/],
41
41
  clientsClaim: true,
42
42
  globPatterns: ['**/*.{js,css,html,png,jpg,jpeg,webp,svg}'],
43
43
  runtimeCaching: [
@@ -95,6 +95,7 @@ export default defineConfig({
95
95
  vite: {
96
96
  plugins: [
97
97
  tailwindcss(),
98
+ VitePWA(pwaOptions),
98
99
  imagetools({
99
100
  // Aggressive image optimization
100
101
  defaultDirectives: () => {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "core-maugli",
3
3
  "description": "Astro & Tailwind CSS blog theme for Maugli.",
4
4
  "type": "module",
5
- "version": "1.2.67",
5
+ "version": "1.2.71",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
Binary file
Binary file
Binary file
package/resize-all.cjs CHANGED
@@ -1,18 +1,18 @@
1
- // resize-all.cjs - рекурсивный ресайз изображений
1
+ // resize-all.cjs - recursive image resizing
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
  const sharp = require('sharp');
5
5
 
6
- // Размеры для генерации
6
+ // Sizes for generation
7
7
  const sizes = [400, 800, 1200];
8
8
 
9
9
  const inputDir = './public';
10
- const processedFiles = new Set(); // Отслеживаем обработанные файлы
10
+ const processedFiles = new Set(); // Track processed files
11
11
 
12
- // Рекурсивная функция для обхода папок
12
+ // Recursive function for directory traversal
13
13
  function processDirectory(dir) {
14
14
  if (!fs.existsSync(dir)) {
15
- console.log(`Папка ${dir} не существует`);
15
+ console.log(`Directory ${dir} does not exist`);
16
16
  return;
17
17
  }
18
18
 
@@ -23,15 +23,15 @@ function processDirectory(dir) {
23
23
  const stat = fs.statSync(itemPath);
24
24
 
25
25
  if (stat.isDirectory()) {
26
- // Рекурсивно обрабатываем подпапки
26
+ // Recursively process subdirectories
27
27
  processDirectory(itemPath);
28
28
  } else if (stat.isFile()) {
29
29
  const ext = path.extname(item).toLowerCase();
30
30
  const baseName = path.basename(item, ext);
31
31
 
32
- // Проверяем, что это изображение и не содержит размер в названии
32
+ // Check if it's an image and doesn't contain size in filename
33
33
  if (['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) {
34
- // Исключаем PWA иконки и служебные файлы
34
+ // Exclude PWA icons and service files
35
35
  const excludePatterns = [
36
36
  'icon-192', 'icon-512', // PWA иконки
37
37
  'favicon', // Фавиконки
@@ -41,31 +41,31 @@ function processDirectory(dir) {
41
41
 
42
42
  const shouldExclude = excludePatterns.some(pattern => baseName.includes(pattern));
43
43
 
44
- // Пропускаем файлы, которые уже содержат размер (например, image-400.webp, image-800-800.webp)
45
- // Улучшенная проверка: пропускаем файлы с -400, -800, -1200 в любом месте названия
44
+ // Skip files that already contain size (e.g., image-400.webp, image-800-800.webp)
45
+ // Enhanced check: skip files with -400, -800, -1200 anywhere in the name
46
46
  const hasResizeSuffix = sizes.some(size => baseName.includes(`-${size}`));
47
47
 
48
48
  if (!hasResizeSuffix && !shouldExclude && !processedFiles.has(itemPath)) {
49
49
  processedFiles.add(itemPath);
50
50
 
51
- console.log(`Обрабатываем: ${itemPath}`);
51
+ console.log(`Processing: ${itemPath}`);
52
52
 
53
53
  sizes.forEach(width => {
54
54
  const outputPath = path.join(path.dirname(itemPath), `${baseName}-${width}${ext}`);
55
55
 
56
- // Проверяем, что файл еще не существует
56
+ // Check if file doesn't already exist
57
57
  if (!fs.existsSync(outputPath)) {
58
58
  sharp(itemPath)
59
59
  .resize(width)
60
60
  .toFile(outputPath, (err) => {
61
61
  if (err) {
62
- console.error(`Ошибка при создании ${outputPath}:`, err.message);
62
+ console.error(`Error creating ${outputPath}:`, err.message);
63
63
  } else {
64
- console.log(`✅ Создан: ${path.relative('./public', outputPath)}`);
64
+ console.log(`✅ Created: ${path.relative('./public', outputPath)}`);
65
65
  }
66
66
  });
67
67
  } else {
68
- console.log(`⏭️ Пропускаем (уже существует): ${path.relative('./public', outputPath)}`);
68
+ console.log(`⏭️ Skipping (already exists): ${path.relative('./public', outputPath)}`);
69
69
  }
70
70
  });
71
71
  }
@@ -74,6 +74,6 @@ function processDirectory(dir) {
74
74
  });
75
75
  }
76
76
 
77
- console.log('🔄 Начинаем ресайз всех изображений...');
77
+ console.log('🔄 Starting image resize process...');
78
78
  processDirectory(inputDir);
79
- console.log('✅ Обработка завершена!');
79
+ console.log('✅ Image processing completed!');
@@ -45,10 +45,10 @@ async function getMaugliConfig() {
45
45
  const configContent = fs.readFileSync(configPath, 'utf8');
46
46
  console.log(colorize('🔍 Reading maugli.config.ts...', 'cyan'));
47
47
 
48
- // Простой и надежный поиск forceUpdate
48
+ // Simple and reliable forceUpdate search
49
49
  let forceUpdate = false;
50
50
 
51
- // Ищем все строки с forceUpdate
51
+ // Search for all lines with forceUpdate
52
52
  const lines = configContent.split('\n');
53
53
  const forceUpdateLines = lines.filter(line => line.includes('forceUpdate'));
54
54
 
@@ -57,9 +57,9 @@ async function getMaugliConfig() {
57
57
  for (const line of forceUpdateLines) {
58
58
  console.log(colorize(` ${line.trim()}`, 'gray'));
59
59
 
60
- // Проверяем разные форматы
60
+ // Check different formats
61
61
  if (line.includes('forceUpdate') && line.includes('true')) {
62
- // Проверяем что это не комментарий
62
+ // Check that this is not a comment
63
63
  const trimmedLine = line.trim();
64
64
  if (!trimmedLine.startsWith('//') && !trimmedLine.startsWith('*')) {
65
65
  forceUpdate = true;
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Копирует netlify.toml только при инициализации нового блога
5
- * НЕ ТРОГАЕТ существующие netlify.toml файлы!
4
+ * Copies netlify.toml only when initializing a new blog
5
+ * DOES NOT TOUCH existing netlify.toml files!
6
6
  */
7
7
 
8
8
  import fs from 'fs';
@@ -23,7 +23,7 @@ function main() {
23
23
  return;
24
24
  }
25
25
 
26
- // Ищем исходный файл в пакете
26
+ // Search for source file in package
27
27
  let sourcePath;
28
28
  const nodeModulesPath = path.join(process.cwd(), 'node_modules', 'core-maugli', 'netlify.toml');
29
29
  if (fs.existsSync(nodeModulesPath)) {
@@ -37,7 +37,7 @@ function main() {
37
37
  return;
38
38
  }
39
39
 
40
- // Копируем файл только для нового блога
40
+ // Copy file only for new blog
41
41
  fs.copyFileSync(sourcePath, targetPath);
42
42
  console.log('✅ netlify.toml created for new blog');
43
43
  console.log('');
@@ -0,0 +1,104 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import sharp from 'sharp';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ // Universal project root detection
10
+ const rootDir = __dirname.includes('node_modules')
11
+ ? path.join(__dirname, '../../..')
12
+ : path.join(__dirname, '..');
13
+
14
+ // Sizes for different content types
15
+ const blogPreviewWidth = 400;
16
+ const blogPreviewHeight = 210;
17
+ const rubricPreviewWidth = 210;
18
+ const rubricPreviewHeight = 214;
19
+
20
+ // Generate in dist instead of public
21
+ const outputDir = path.join(rootDir, 'dist');
22
+
23
+ // Function to create preview in dist
24
+ async function createPreviewForBuild(sourcePath, outputPath, width, height) {
25
+ const previewDir = path.dirname(outputPath);
26
+ if (!fs.existsSync(previewDir)) {
27
+ fs.mkdirSync(previewDir, { recursive: true });
28
+ }
29
+
30
+ if (fs.existsSync(outputPath)) {
31
+ return; // Preview already exists
32
+ }
33
+
34
+ try {
35
+ await sharp(sourcePath)
36
+ .resize(width, height, { fit: 'cover' })
37
+ .toFile(outputPath);
38
+ console.log(`✅ Preview created: ${path.relative(rootDir, outputPath)}`);
39
+ } catch (error) {
40
+ console.error(`❌ Error creating preview ${outputPath}:`, error.message);
41
+ }
42
+ }
43
+
44
+ // Function to process directory
45
+ async function processDirectory(sourceDir, outputSubDir) {
46
+ if (!fs.existsSync(sourceDir)) {
47
+ return;
48
+ }
49
+
50
+ const items = fs.readdirSync(sourceDir);
51
+
52
+ for (const item of items) {
53
+ const sourcePath = path.join(sourceDir, item);
54
+ const stat = fs.statSync(sourcePath);
55
+
56
+ if (stat.isDirectory()) {
57
+ if (item === 'previews') continue; // Skip preview folders
58
+ await processDirectory(sourcePath, path.join(outputSubDir, item));
59
+ } else if (item.match(/\.(webp|jpg|jpeg|png)$/i)) {
60
+ const ext = path.extname(item);
61
+ const name = path.basename(item, ext);
62
+
63
+ // Skip files that already contain size suffix
64
+ const hasResizeSuffix = [400, 800, 1200].some(size => name.includes(`-${size}`));
65
+ if (hasResizeSuffix) continue;
66
+
67
+ // Determine preview size
68
+ let previewWidth, previewHeight;
69
+ if (sourcePath.includes('/img/default/') && (name.includes('rubric') || name.includes('tag'))) {
70
+ previewWidth = rubricPreviewWidth;
71
+ previewHeight = rubricPreviewHeight;
72
+ } else {
73
+ previewWidth = blogPreviewWidth;
74
+ previewHeight = blogPreviewHeight;
75
+ }
76
+
77
+ // Create preview
78
+ const outputDir = path.join(rootDir, 'dist', outputSubDir, 'previews');
79
+ const outputPath = path.join(outputDir, `${name}${ext}`);
80
+
81
+ console.log(`🎭 Creating preview for build: ${name}`);
82
+ await createPreviewForBuild(sourcePath, outputPath, previewWidth, previewHeight);
83
+ }
84
+ }
85
+ }
86
+
87
+ // Main function
88
+ async function generatePreviewsForBuild() {
89
+ console.log('🚀 Starting preview generation for build...');
90
+
91
+ // Process system folders
92
+ await processDirectory(path.join(rootDir, 'public/img/default'), 'img/default');
93
+ await processDirectory(path.join(rootDir, 'public/img/examples'), 'img/examples');
94
+
95
+ // Process user images if they exist
96
+ const pageImagesDir = path.join(rootDir, 'public/img/page-images');
97
+ if (fs.existsSync(pageImagesDir)) {
98
+ await processDirectory(pageImagesDir, 'img/page-images');
99
+ }
100
+
101
+ console.log('✅ Preview generation for build completed!');
102
+ }
103
+
104
+ generatePreviewsForBuild().catch(console.error);
@@ -6,15 +6,15 @@ import { fileURLToPath } from 'url';
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
- // Универсальное определение корня проекта
9
+ // Universal project root detection
10
10
  const rootDir = __dirname.includes('node_modules')
11
11
  ? path.join(__dirname, '../../..')
12
12
  : path.join(__dirname, '..');
13
13
 
14
- // Размеры для разных типов контента
14
+ // Sizes for different content types
15
15
  const blogPreviewWidth = 400;
16
16
  const blogPreviewHeight = 210;
17
- const rubricPreviewWidth = 210; // Увеличенный размер для качества на retina дисплеях (105px * 2)
17
+ const rubricPreviewWidth = 210; // Increased size for retina display quality (105px * 2)
18
18
  const rubricPreviewHeight = 214; // Увеличенный размер для качества на retina дисплеях (107px * 2)
19
19
  const authorPreviewWidth = 192; // Квадратный размер для аватарок
20
20
  const authorPreviewHeight = 192;
@@ -108,7 +108,7 @@ function extractImagePaths() {
108
108
  return Array.from(imagePaths);
109
109
  }
110
110
 
111
- // Функция для очистки всех существующих превьюшек
111
+ // Function to clean all existing preview images
112
112
  function cleanupExistingPreviews() {
113
113
  const publicDir = path.join(rootDir, 'public');
114
114
 
@@ -135,7 +135,7 @@ function cleanupExistingPreviews() {
135
135
  removePreviewDirs(publicDir);
136
136
  }
137
137
 
138
- // Функция для создания превьюшки
138
+ // Function to create preview image
139
139
  async function createPreview(imagePath) {
140
140
  const fullImagePath = path.join(rootDir, 'public', imagePath.replace(/^\//, ''));
141
141
 
@@ -149,7 +149,7 @@ async function createPreview(imagePath) {
149
149
  const name = path.basename(fullImagePath, ext);
150
150
  const previewPath = path.join(dir, 'previews', `${name}${ext}`);
151
151
 
152
- // Определяем размер превью в зависимости от типа изображения
152
+ // Determine preview size based on image type
153
153
  let previewWidth, previewHeight;
154
154
  if (imagePath.includes('/img/default/') && (name.includes('rubric') || name.includes('tag'))) {
155
155
  previewWidth = rubricPreviewWidth;
@@ -171,7 +171,7 @@ async function createPreview(imagePath) {
171
171
  fs.mkdirSync(previewDir, { recursive: true });
172
172
  }
173
173
 
174
- // Если превью уже существует пропускаем генерацию
174
+ // If preview already exists - skip generation
175
175
  if (fs.existsSync(previewPath)) {
176
176
  // console.log(`Preview already exists: ${previewPath}`);
177
177
  return;
@@ -188,7 +188,7 @@ async function createPreview(imagePath) {
188
188
 
189
189
  // Основная функция
190
190
  async function generatePreviews() {
191
- // Очистка превью только если явно указано (например, через переменную)
191
+ // Clean previews only if explicitly specified (e.g., via environment variable)
192
192
  const CLEAN_PREVIEWS = process.env.CLEAN_PREVIEWS === '1';
193
193
  if (CLEAN_PREVIEWS) {
194
194
  console.log('Cleaning up existing previews...');
@@ -1,16 +1,16 @@
1
- // optimize-images.cjs - продвинутая оптимизация изображений с Sharp
1
+ // optimize-images.cjs - advanced image optimization with Sharp
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
  const sharp = require('sharp');
5
5
 
6
- // Размеры для генерации
6
+ // Sizes for generation
7
7
  const sizes = [400, 800, 1200];
8
8
 
9
- // Настройки оптимизации для разных форматов
9
+ // Optimization settings for different formats
10
10
  const optimizationSettings = {
11
11
  webp: {
12
12
  quality: 80,
13
- effort: 6, // Максимальное сжатие (0-6)
13
+ effort: 6, // Maximum compression (0-6)
14
14
  lossless: false
15
15
  },
16
16
  jpeg: {
@@ -20,7 +20,7 @@ const optimizationSettings = {
20
20
  },
21
21
  png: {
22
22
  quality: 90,
23
- compressionLevel: 9, // Максимальное сжатие
23
+ compressionLevel: 9, // Maximum compression
24
24
  progressive: true
25
25
  }
26
26
  };
@@ -28,13 +28,13 @@ const optimizationSettings = {
28
28
  const inputDir = './public';
29
29
  const processedFiles = new Set();
30
30
 
31
- // Функция для оптимизации изображения
31
+ // Function for image optimization
32
32
  async function optimizeImage(inputPath, outputPath, width = null) {
33
33
  try {
34
34
  const ext = path.extname(outputPath).toLowerCase();
35
35
  let sharpInstance = sharp(inputPath);
36
36
 
37
- // Ресайз если указана ширина
37
+ // Resize if width is specified
38
38
  if (width) {
39
39
  sharpInstance = sharpInstance.resize(width, null, {
40
40
  withoutEnlargement: true,
@@ -42,7 +42,7 @@ async function optimizeImage(inputPath, outputPath, width = null) {
42
42
  });
43
43
  }
44
44
 
45
- // Применяем оптимизацию в зависимости от формата
45
+ // Apply optimization based on format
46
46
  switch (ext) {
47
47
  case '.webp':
48
48
  await sharpInstance
@@ -64,23 +64,23 @@ async function optimizeImage(inputPath, outputPath, width = null) {
64
64
  break;
65
65
 
66
66
  default:
67
- // Для других форматов используем WebP по умолчанию
67
+ // For other formats use WebP by default
68
68
  const webpPath = outputPath.replace(/\.[^.]+$/, '.webp');
69
69
  await sharpInstance
70
70
  .webp(optimizationSettings.webp)
71
71
  .toFile(webpPath);
72
- console.log(`🔄 Конвертирован в WebP: ${path.relative('./public', webpPath)}`);
72
+ console.log(`🔄 Converted to WebP: ${path.relative('./public', webpPath)}`);
73
73
  return;
74
74
  }
75
75
 
76
- console.log(`✅ Оптимизирован: ${path.relative('./public', outputPath)}`);
76
+ console.log(`✅ Optimized: ${path.relative('./public', outputPath)}`);
77
77
 
78
78
  } catch (err) {
79
- console.error(`❌ Ошибка оптимизации ${outputPath}:`, err.message);
79
+ console.error(`❌ Optimization error ${outputPath}:`, err.message);
80
80
  }
81
81
  }
82
82
 
83
- // Получение статистики размера файла
83
+ // Get file size statistics
84
84
  function getFileSizeStats(originalPath, optimizedPath) {
85
85
  if (!fs.existsSync(originalPath) || !fs.existsSync(optimizedPath)) {
86
86
  return null;
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // squoosh-optimize.js - автоматическая оптимизация через Squoosh CLI
3
+ // squoosh-optimize.js - automatic optimization through Squoosh CLI
4
4
  import { execSync } from 'child_process';
5
5
  import fs from 'fs';
6
6
  import path from 'path';
@@ -12,7 +12,7 @@ const __dirname = path.dirname(__filename);
12
12
  const projectRoot = path.resolve(__dirname, '..');
13
13
  const publicDir = path.join(projectRoot, 'public');
14
14
 
15
- // Функция для получения всех изображений
15
+ // Function to get all images
16
16
  function getAllImages(dir, images = []) {
17
17
  const items = fs.readdirSync(dir);
18
18
 
@@ -25,7 +25,7 @@ function getAllImages(dir, images = []) {
25
25
  } else if (stat.isFile()) {
26
26
  const ext = path.extname(item).toLowerCase();
27
27
  if (['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) {
28
- // Пропускаем уже обработанные ресайзы
28
+ // Skip already processed resized images
29
29
  const baseName = path.basename(item, ext);
30
30
  if (!/-\d+$/.test(baseName)) {
31
31
  images.push(itemPath);
@@ -37,7 +37,7 @@ function getAllImages(dir, images = []) {
37
37
  return images;
38
38
  }
39
39
 
40
- // Функция для создания временной директории
40
+ // Function to create temporary directory
41
41
  function createTempDir() {
42
42
  const tempDir = path.join(projectRoot, '.temp-optimization');
43
43
  if (!fs.existsSync(tempDir)) {
@@ -107,29 +107,29 @@ async function optimizeWithSquoosh() {
107
107
  const savings = originalSize - optimizedSize;
108
108
  const savingsPercent = Math.round((savings / originalSize) * 100);
109
109
 
110
- // Заменяем оригинал на оптимизированную версию
110
+ // Replace original with optimized version
111
111
  fs.copyFileSync(optimizedPath, originalPath);
112
112
 
113
113
  totalSavings += savings;
114
114
  processedCount++;
115
115
 
116
- console.log(`💾 ${path.relative(publicDir, originalPath)}: ${Math.round(savings/1024)}KB экономии (${savingsPercent}%)`);
116
+ console.log(`💾 ${path.relative(publicDir, originalPath)}: ${Math.round(savings/1024)}KB saved (${savingsPercent}%)`);
117
117
  }
118
118
  }
119
119
  }
120
120
  });
121
121
 
122
- console.log(`\n🎉 Обработано ${processedCount} изображений`);
123
- console.log(`💰 Общая экономия: ${Math.round(totalSavings/1024)}KB`);
122
+ console.log(`\n🎉 Processed ${processedCount} images`);
123
+ console.log(`💰 Total savings: ${Math.round(totalSavings/1024)}KB`);
124
124
 
125
125
  } catch (squooshError) {
126
- console.error('❌ Ошибка Squoosh CLI:', squooshError.message);
127
- console.log('🔄 Переключаемся на Sharp оптимизацию...');
126
+ console.error('❌ Squoosh CLI error:', squooshError.message);
127
+ console.log('🔄 Switching to Sharp optimization...');
128
128
  return false;
129
129
  }
130
130
 
131
131
  } finally {
132
- // Очищаем временные файлы
132
+ // Clean up temporary files
133
133
  if (fs.existsSync(tempDir)) {
134
134
  fs.rmSync(tempDir, { recursive: true, force: true });
135
135
  }
@@ -138,7 +138,7 @@ async function optimizeWithSquoosh() {
138
138
  return true;
139
139
  }
140
140
 
141
- // Запуск если вызван напрямую
141
+ // Run if called directly
142
142
  if (import.meta.url === `file://${process.argv[1]}`) {
143
143
  optimizeWithSquoosh().catch(console.error);
144
144
  }
@@ -1,21 +1,22 @@
1
- #!/usr/bin/env nconst CURRENT_VERSION = '1.2.48';onst CURRENT_VERSION = '1.2.46';de
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Скрипт для централизованного обновления всех блогов до последней версии core-maugli
4
+ * Script for centralized updating of all blogs to the latest core-maugli version
5
5
  *
6
- * Использование:
7
- * node scripts/update-all-blogs.js [путь_к_проекту]
6
+ * Usage:
7
+ * node scripts/update-all-blogs.js [project_path]
8
8
  *
9
- * Или для множественного обновления:
9
+ * Or for multiple updates:
10
10
  * node scripts/update-all-blogs.js /path/to/blogs/project1 /path/to/blogs/project2
11
11
  */
12
12
 
13
13
  import fs from 'fs';
14
14
  import path from 'path';
15
+ import { execSync } from 'child_process';
15
16
 
16
- const CURRENT_VERSION = '1.2.44';
17
+ const CURRENT_VERSION = '1.2.70';
17
18
 
18
- // Правильные скрипты для package.json
19
+ // Correct scripts for package.json
19
20
  const CORRECT_SCRIPTS = {
20
21
  "typograf": "node typograf-batch.js",
21
22
  "dev": "node resize-all.cjs && node scripts/generate-previews.js && astro dev",
@@ -43,7 +44,7 @@ const CORRECT_SCRIPTS = {
43
44
  "generate-previews": "node scripts/generate-previews.js"
44
45
  };
45
46
 
46
- // Файлы скриптов, которые нужно скопировать
47
+ // Script files that need to be copied
47
48
  const REQUIRED_SCRIPTS = [
48
49
  'scripts/flatten-images.cjs',
49
50
  'scripts/optimize-images.cjs',
@@ -97,20 +98,20 @@ function updateBlogProject(projectPath) {
97
98
  log(`Updating project: ${absolutePath}`, 'info');
98
99
 
99
100
  try {
100
- // 1. Читаем package.json
101
+ // 1. Read package.json
101
102
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
102
103
 
103
- // 2. Проверяем, что это проект core-maugli
104
+ // 2. Check that this is a core-maugli project
104
105
  if (packageJson.name !== 'core-maugli') {
105
106
  log(`Skipping: not a core-maugli project (${packageJson.name})`, 'warning');
106
107
  return false;
107
108
  }
108
109
 
109
- // 3. Обновляем версию
110
+ // 3. Update version
110
111
  const oldVersion = packageJson.version;
111
112
  packageJson.version = CURRENT_VERSION;
112
113
 
113
- // 4. Обновляем скрипты
114
+ // 4. Update scripts
114
115
  let scriptsUpdated = false;
115
116
  for (const [scriptName, scriptValue] of Object.entries(CORRECT_SCRIPTS)) {
116
117
  if (packageJson.scripts[scriptName] !== scriptValue) {
@@ -119,10 +120,10 @@ function updateBlogProject(projectPath) {
119
120
  }
120
121
  }
121
122
 
122
- // 5. Сохраняем package.json
123
+ // 5. Save package.json
123
124
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4));
124
125
 
125
- // 6. Копируем недостающие скрипты
126
+ // 6. Copy missing scripts
126
127
  const scriptsDir = path.join(absolutePath, 'scripts');
127
128
  if (!fs.existsSync(scriptsDir)) {
128
129
  fs.mkdirSync(scriptsDir, { recursive: true });
@@ -7,7 +7,7 @@ import { fileURLToPath, pathToFileURL } from 'url';
7
7
  const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = path.dirname(__filename);
9
9
 
10
- // Определяем корневые папки
10
+ // Define root directories
11
11
  const isInNodeModules = __dirname.includes('node_modules');
12
12
  const isSourceProject = !isInNodeModules && (
13
13
  __dirname.includes('core-maugli-blog') ||
@@ -83,7 +83,7 @@ async function updateConfigVersion() {
83
83
 
84
84
  let updated = false;
85
85
 
86
- // Обновляем версию зависимости
86
+ // Update dependency version
87
87
  if (userPackageData.dependencies && userPackageData.dependencies['core-maugli']) {
88
88
  const currentVersion = userPackageData.dependencies['core-maugli'];
89
89
  if (currentVersion !== `^${newVersion}`) {
@@ -100,14 +100,14 @@ async function updateConfigVersion() {
100
100
  }
101
101
  }
102
102
 
103
- // Обновляем build скрипт для включения генерации превью
103
+ // Update build script to include preview generation
104
104
  if (userPackageData.scripts) {
105
105
  const expectedBuildScript = "node typograf-batch.js && node scripts/generate-previews.js && node scripts/verify-assets.js && astro build";
106
106
  const currentBuildScript = userPackageData.scripts.build;
107
107
 
108
- // Проверяем, содержит ли build скрипт генерацию превью
108
+ // Check if build script contains preview generation
109
109
  if (currentBuildScript && !currentBuildScript.includes('generate-previews.js')) {
110
- // Добавляем генерацию превью в build процесс
110
+ // Add preview generation to build process
111
111
  if (currentBuildScript.includes('astro build')) {
112
112
  userPackageData.scripts.build = currentBuildScript.replace(
113
113
  'astro build',
@@ -119,9 +119,6 @@ async function updateConfigVersion() {
119
119
  }
120
120
  }
121
121
 
122
- // Создаем файл sw.js.astro для исправления PWA маршрутизации
123
- await createPWAServiceWorkerFile();
124
-
125
122
  if (updated) {
126
123
  await fs.writeFile(userPackageJsonPath, JSON.stringify(userPackageData, null, 2) + '\n', 'utf-8');
127
124
  console.log(`📦 Updated package.json with version ^${newVersion}`);
@@ -140,42 +137,6 @@ async function updateConfigVersion() {
140
137
  }
141
138
  }
142
139
 
143
- async function createPWAServiceWorkerFile() {
144
- try {
145
- const swPath = path.join(userRoot, 'src/pages/sw.js.astro');
146
-
147
- // Проверяем, существует ли уже файл
148
- try {
149
- await fs.stat(swPath);
150
- console.log('🔧 PWA service worker file already exists, skipping...');
151
- return;
152
- } catch {
153
- // Файл не существует, создаем его
154
- }
155
-
156
- const swContent = `---
157
- // Astro page для обработки service worker запросов PWA
158
- // Это исправляет предупреждения маршрутизации в dev режиме
159
- ---
160
-
161
- <script>
162
- // Перенаправляем на актуальный service worker
163
- if (typeof window !== 'undefined') {
164
- window.location.href = '/dev-dist/sw.js';
165
- }
166
- </script>`;
167
-
168
- // Создаем папку если её нет
169
- await fs.mkdir(path.dirname(swPath), { recursive: true });
170
-
171
- // Создаем файл
172
- await fs.writeFile(swPath, swContent, 'utf-8');
173
- console.log('🔧 Created PWA service worker file: src/pages/sw.js.astro');
174
- } catch (error) {
175
- console.warn('Warning: Could not create PWA service worker file:', error.message);
176
- }
177
- }
178
-
179
140
  async function copyDirectory(src, dest) {
180
141
  try {
181
142
  await fs.mkdir(dest, { recursive: true });
@@ -243,7 +204,7 @@ async function updateComponents() {
243
204
  return;
244
205
  }
245
206
 
246
- // Дополнительная проверка
207
+ // Additional check
247
208
  if (packageRoot === userRoot) {
248
209
  console.log('⚠️ Skipping component update (packageRoot equals userRoot)');
249
210
  return;
@@ -286,7 +247,7 @@ async function updateComponents() {
286
247
  // Обрабатываем стили отдельно
287
248
  await updateStyles();
288
249
 
289
- // Обновляем версию в конфиге
250
+ // Update version in config
290
251
  await updateConfigVersion();
291
252
 
292
253
  console.log(`✅ Updated ${updatedCount} component directories/files`);
@@ -7,7 +7,7 @@ import BaseLayout from '../layouts/BaseLayout.astro';
7
7
 
8
8
  export async function getStaticPaths() {
9
9
  const pages = await getCollection('pages');
10
-
10
+
11
11
  return pages.map((page) => {
12
12
  return {
13
13
  params: { id: page.id },
@@ -20,12 +20,6 @@ type Props = { page: CollectionEntry<'pages'> };
20
20
 
21
21
  const { page } = Astro.props;
22
22
 
23
- // Блокируем обработку системных файлов PWA
24
- const pwaFiles = ['sw.js', 'manifest.json', 'workbox-', 'service-worker.js'];
25
- if (pwaFiles.some(file => Astro.url.pathname.includes(file))) {
26
- return new Response(null, { status: 404 });
27
- }
28
-
29
23
  const { title, seo } = page.data;
30
24
  const { Content } = await render(page);
31
25
 
@@ -11,7 +11,7 @@ export async function getFeaturedPosts() {
11
11
  .sort((a, b) => b.data.publishDate.getTime() - a.data.publishDate.getTime())
12
12
  .slice(0, 3); // Максимум 3 featured поста
13
13
  } catch (error) {
14
- console.error('Ошибка при получении featured постов:', error);
14
+ console.error('Error getting featured posts:', error);
15
15
  return [];
16
16
  }
17
17
  }
@@ -24,7 +24,7 @@ export async function getAllPosts() {
24
24
  const allPosts = await getFilteredCollection('blog');
25
25
  return allPosts.sort((a, b) => b.data.publishDate.getTime() - a.data.publishDate.getTime());
26
26
  } catch (error) {
27
- console.error('Ошибка при получении постов:', error);
27
+ console.error('Error getting posts:', error);
28
28
  return [];
29
29
  }
30
30
  }
package/src/middleware.ts DELETED
@@ -1,21 +0,0 @@
1
- import { defineMiddleware } from 'astro:middleware';
2
-
3
- export const onRequest = defineMiddleware(async (context, next) => {
4
- // Список системных файлов PWA, которые не должны обрабатываться динамическими маршрутами
5
- const pwaFiles = [
6
- '/sw.js',
7
- '/manifest.json',
8
- '/manifest.webmanifest',
9
- '/workbox-',
10
- '/service-worker.js'
11
- ];
12
-
13
- // Проверяем, является ли запрос системным файлом PWA
14
- if (pwaFiles.some(file => context.url.pathname.startsWith(file))) {
15
- // Если это системный файл, пропускаем обработку Astro и позволяем Vite/PWA плагину обработать его
16
- return next();
17
- }
18
-
19
- // Для всех остальных запросов продолжаем обычную обработку
20
- return next();
21
- });
@@ -1,8 +0,0 @@
1
- ---
2
- // Этот файл блокирует обработку /sw.js через динамический маршрут [...]
3
- // Фактический service worker генерируется VitePWA плагином
4
- ---
5
- <script>
6
- // Redirect to actual service worker generated by VitePWA
7
- window.location.href = '/dev-dist/sw.js';
8
- </script>