core-maugli 1.2.2 → 1.2.4

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.
Files changed (92) hide show
  1. package/README.md +29 -15
  2. package/package.json +6 -13
  3. package/public/img/examples/blog/previews/post-1-avtomatizaciya-marketinga-kak-ii-osvobozhdaet-predprinimatelei-ot-cifrovogo-rabstva.webp +0 -0
  4. package/public/img/examples/blog/previews/post-2-avtomatizaciya-kontenta-kak-neiroseti-ubivayut-perfekcionizm-v-biznese.webp +0 -0
  5. package/public/img/examples/blog/previews/post-3-laik-ne-valyuta-kak-avtomatizaciya-marketinga-spasaet-ot-lozhnyh-metrik.webp +0 -0
  6. package/public/img/examples/blog/previews/post-5-5-fatalnyh-oshibok-marketinga-kotorye-ubivayut-startapy-na-starte.webp +0 -0
  7. package/public/img/examples/blog/previews/post-6-5-strategii-kontent-marketinga-dlya-startapov-avtomatizaciya-i-revolyuciya.webp +0 -0
  8. package/public/img/examples/blog/previews/post-7-viralnyi-kontent-ne-udacha-a-strategiya-avtomatizaciya-marketinga.webp +0 -0
  9. package/public/img/examples/blog/previews/post-agent-experience-mcp-biznes-v-epohu-ii-agentov.webp +0 -0
  10. package/public/img/examples/blog/previews/post_11.webp +0 -0
  11. package/public/img/examples/blog/previews/post_12.webp +0 -0
  12. package/public/img/examples/blog/previews/post_1_jsonld_guide.webp +0 -0
  13. package/public/img/examples/blog/previews/test-post.webp +0 -0
  14. package/public/img/examples/blog/previews/tr-post-1.webp +0 -0
  15. package/public/img/examples/products/previews/product_1.webp +0 -0
  16. package/public/img/examples/products/previews/product_2.webp +0 -0
  17. package/public/img/examples/projects/previews/project_1.webp +0 -0
  18. package/public/img/examples/projects/previews/project_2.webp +0 -0
  19. package/scripts/generate-previews.js +175 -0
  20. package/scripts/update-components.js +166 -0
  21. package/scripts/upgrade-config.js +23 -3
  22. package/src/components/LanguageSwitcher.astro +2 -16
  23. package/astro.config.mjs +0 -92
  24. package/bin/init.js +0 -201
  25. package/public/img/default/autor_default.webp +0 -0
  26. package/public/img/default/blog_default.webp +0 -0
  27. package/public/img/default/default.webp +0 -0
  28. package/public/img/default/product_default.webp +0 -0
  29. package/public/img/default/project_default.webp +0 -0
  30. package/public/img/default/rubric_default.webp +0 -0
  31. package/public/img/default/test.webp +0 -0
  32. package/public/img/default/test2.webp +0 -0
  33. package/resize-all.cjs +0 -29
  34. package/src/i18n/de.json +0 -126
  35. package/src/i18n/en.json +0 -126
  36. package/src/i18n/es.json +0 -126
  37. package/src/i18n/fr.json +0 -126
  38. package/src/i18n/index.ts +0 -10
  39. package/src/i18n/ja.json +0 -126
  40. package/src/i18n/languages.ts +0 -23
  41. package/src/i18n/pt.json +0 -126
  42. package/src/i18n/ru.json +0 -123
  43. package/src/i18n/zh.json +0 -126
  44. package/src/icons/ArrowLeft.astro +0 -13
  45. package/src/icons/ArrowRight.astro +0 -13
  46. package/src/icons/flags/brazil.svg +0 -14
  47. package/src/icons/flags/china.svg +0 -15
  48. package/src/icons/flags/france.svg +0 -12
  49. package/src/icons/flags/germany.svg +0 -12
  50. package/src/icons/flags/japan.svg +0 -11
  51. package/src/icons/flags/russia.svg +0 -12
  52. package/src/icons/flags/spain.svg +0 -12
  53. package/src/icons/flags/united arab emirates.svg +0 -13
  54. package/src/icons/flags/united states.svg +0 -15
  55. package/src/icons/socials/BlueskyIcon.astro +0 -9
  56. package/src/icons/socials/EmailIcon.astro +0 -8
  57. package/src/icons/socials/LinkedinIcon.astro +0 -9
  58. package/src/icons/socials/MastodonIcon.astro +0 -9
  59. package/src/icons/socials/MediumIcon.astro +0 -9
  60. package/src/icons/socials/RedditIcon.astro +0 -11
  61. package/src/icons/socials/TelegramIcon.astro +0 -11
  62. package/src/icons/socials/TwitterIcon.astro +0 -9
  63. package/src/layouts/BaseLayout.astro +0 -59
  64. package/src/pages/404.astro +0 -24
  65. package/src/pages/[...id].astro +0 -50
  66. package/src/pages/about.astro +0 -0
  67. package/src/pages/authors/[...page].astro +0 -105
  68. package/src/pages/authors/[id].astro +0 -175
  69. package/src/pages/blog/[...page].astro +0 -59
  70. package/src/pages/blog/[id].astro +0 -175
  71. package/src/pages/index.astro +0 -90
  72. package/src/pages/products/[...page].astro +0 -50
  73. package/src/pages/products/[id].astro +0 -221
  74. package/src/pages/projects/[...page].astro +0 -74
  75. package/src/pages/projects/[id].astro +0 -165
  76. package/src/pages/projects/tags/[id]/[...page].astro +0 -58
  77. package/src/pages/rss.xml.js +0 -5
  78. package/src/pages/tags/[id]/[...page].astro +0 -110
  79. package/src/pages/tags/index.astro +0 -124
  80. package/src/scripts/infoCardFadeIn.js +0 -22
  81. package/src/styles/global.css +0 -273
  82. package/src/utils/common-utils.ts +0 -0
  83. package/src/utils/content-loader.ts +0 -14
  84. package/src/utils/data-utils.ts +0 -49
  85. package/src/utils/featuredManager.ts +0 -118
  86. package/src/utils/posts.ts +0 -43
  87. package/src/utils/reading-time.ts +0 -28
  88. package/src/utils/remark-slugify.js +0 -8
  89. package/src/utils/rss.ts +0 -23
  90. package/tsconfig.json +0 -8
  91. package/typograf-batch.js +0 -49
  92. package/vite.config.js +0 -11
package/README.md CHANGED
@@ -87,6 +87,19 @@ Your blog will be available at `http://localhost:4321/`
87
87
  npm run build
88
88
  ```
89
89
 
90
+ ## Component Updates & Customization
91
+
92
+ **Important**: Maugli Blog is designed for centralized component updates. All components (`src/components/`, `src/layouts/`, `src/pages/`, etc.) are automatically updated to the latest version when you update the package with `npm install --save core-maugli@latest`. This ensures you always receive the latest features, bug fixes, and improvements.
93
+
94
+ This centralized update approach **does not affect**:
95
+
96
+ - Your content (`src/content/`)
97
+ - Your Maugli configuration (`src/config/maugli.config.ts`)
98
+ - Your custom styles (`src/styles/global.css` - preserved if customized)
99
+ - Your project settings (`package.json`, `astro.config.mjs`, etc.)
100
+
101
+ Only the core blog components are updated, while your customizations and settings remain intact.
102
+
90
103
  `npm run build` runs [`scripts/verify-assets.js`](scripts/verify-assets.js)
91
104
  before the Astro build. This script checks the SHA-256 hashes of the
92
105
  floating label component and footer badge to ensure they haven't been
@@ -193,18 +206,18 @@ npx core-maugli init .
193
206
 
194
207
  ### Useful npm scripts
195
208
 
196
- | Script | Description |
197
- | -------------------------------- | ------------------------------------------- |
198
- | `npm run dev` | Start local dev server |
199
- | `npm start` | Alias for `npm run dev` |
209
+ | Script | Description |
210
+ | -------------------------------- | ----------------------------------------------------------- |
211
+ | `npm run dev` | Start local dev server |
212
+ | `npm start` | Alias for `npm run dev` |
200
213
  | `npm run build` | Format content, verify assets, then create production build |
201
- | `npm run typograf` | Run typograf on all posts |
202
- | `npm run astro` | Access the Astro CLI |
203
- | `npm run featured:add <slug>` | Mark a post as featured |
204
- | `npm run featured:remove <slug>` | Remove featured mark from a post |
205
- | `npm run featured:list` | List all featured posts |
206
- | `npm run upgrade` | Manually update `maugli.config.ts` |
207
- | `npm run backup-update` | Backup key files then run `npm update` |
214
+ | `npm run typograf` | Run typograf on all posts |
215
+ | `npm run astro` | Access the Astro CLI |
216
+ | `npm run featured:add <slug>` | Mark a post as featured |
217
+ | `npm run featured:remove <slug>` | Remove featured mark from a post |
218
+ | `npm run featured:list` | List all featured posts |
219
+ | `npm run upgrade` | Manually update `maugli.config.ts` |
220
+ | `npm run backup-update` | Backup key files then run `npm update` |
208
221
 
209
222
  ## Checking installed version
210
223
 
@@ -214,14 +227,16 @@ See which version of the theme is installed:
214
227
  npm list core-maugli
215
228
  ```
216
229
 
217
- ## Updating
230
+ ## Updating the theme
218
231
 
219
- Upgrade to the latest release:
232
+ To update to the latest version of core-maugli, use:
220
233
 
221
234
  ```bash
222
- npm update
235
+ npm install core-maugli@latest --save
223
236
  ```
224
237
 
238
+ If you just run `npm install core-maugli`, it will install the version specified in your package.json. Only with `--save` (или вручную обновив package.json) вы получите самую свежую версию.
239
+
225
240
  To back up key files and then update, run:
226
241
 
227
242
  ```bash
@@ -244,4 +259,3 @@ commercial license.
244
259
 
245
260
  Contact <licensing@maugli.cfd> or visit
246
261
  <https://maugli.cfd/licensing> for more information.
247
-
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.2",
5
+ "version": "1.2.4",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
@@ -21,15 +21,17 @@
21
21
  "typograf": "node typograf-batch.js",
22
22
  "dev": "astro dev",
23
23
  "start": "astro dev",
24
- "build": "node typograf-batch.js && node scripts/verify-assets.js && astro build",
24
+ "build": "node typograf-batch.js && node scripts/generate-previews.js && node scripts/verify-assets.js && astro build",
25
25
  "test": "node tests/examplesFilter.test.ts",
26
26
  "astro": "astro",
27
27
  "featured:add": "node scripts/featured.js add",
28
28
  "featured:remove": "node scripts/featured.js remove",
29
29
  "featured:list": "node scripts/featured.js list",
30
30
  "upgrade": "node scripts/upgrade-config.js",
31
+ "update-components": "node scripts/update-components.js",
31
32
  "backup-update": "node scripts/update-with-backup.js",
32
- "postinstall": "node scripts/upgrade-config.js"
33
+ "postinstall": "node scripts/upgrade-config.js",
34
+ "generate-previews": "node scripts/generate-previews.js"
33
35
  },
34
36
  "dependencies": {
35
37
  "@astrojs/mdx": "^4.3.0",
@@ -61,17 +63,8 @@
61
63
  "files": [
62
64
  "src",
63
65
  "public",
64
- "scripts",
65
- "typograf-batch.js",
66
- "resize-all.cjs",
67
- "bin",
68
- "astro.config.mjs",
69
- "tsconfig.json",
70
- "vite.config.js",
71
- "LICENSE",
72
- "README.md"
66
+ "scripts"
73
67
  ],
74
- "main": "bin/index.js",
75
68
  "bin": {
76
69
  "core-maugli": "bin/index.js"
77
70
  }
@@ -0,0 +1,175 @@
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
+ // Универсальное определение корня проекта
10
+ const rootDir = __dirname.includes('node_modules')
11
+ ? path.join(__dirname, '../../..')
12
+ : path.join(__dirname, '..');
13
+
14
+ const previewWidth = 400;
15
+ const previewHeight = 210;
16
+
17
+ // Функция для извлечения путей изображений из markdown файлов
18
+ function extractImagePaths() {
19
+ const imagePaths = new Set();
20
+ const contentDir = path.join(rootDir, 'src/content');
21
+
22
+ function scanDirectory(dir) {
23
+ if (!fs.existsSync(dir)) return;
24
+
25
+ const items = fs.readdirSync(dir);
26
+
27
+ for (const item of items) {
28
+ const itemPath = path.join(dir, item);
29
+ const stat = fs.statSync(itemPath);
30
+
31
+ if (stat.isDirectory()) {
32
+ scanDirectory(itemPath);
33
+ } else if (item.endsWith('.md') || item.endsWith('.mdx')) {
34
+ const content = fs.readFileSync(itemPath, 'utf-8');
35
+
36
+ // Извлекаем изображения из frontmatter (image: путь)
37
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
38
+ if (frontmatterMatch) {
39
+ const frontmatter = frontmatterMatch[1];
40
+ // Улучшенные регулярки для frontmatter
41
+ const imageMatches = frontmatter.match(/(?:^|\n)\s*(?:image|src):\s*['"]*([^'">\s\n]+)['"]*(?:\s|$)/g);
42
+ if (imageMatches) {
43
+ imageMatches.forEach(match => {
44
+ const imagePath = match.replace(/.*?(?:image|src):\s*['"]*/, '').replace(/['"]*\s*$/, '');
45
+ if (imagePath && !imagePath.startsWith('http') && imagePath.includes('/') && !imagePath.includes('authors/')) {
46
+ imagePaths.add(imagePath);
47
+ }
48
+ });
49
+ }
50
+ }
51
+
52
+ // Извлекаем изображения из содержимого markdown (![](путь) и <img src="путь">)
53
+ const imgMatches = content.match(/!\[.*?\]\(([^)]+)\)|<img[^>]+src\s*=\s*['"]*([^'">\s]+)['"]*[^>]*>/g);
54
+ if (imgMatches) {
55
+ imgMatches.forEach(match => {
56
+ let imagePath;
57
+ if (match.startsWith('![')) {
58
+ imagePath = match.match(/!\[.*?\]\(([^)]+)\)/)?.[1];
59
+ } else {
60
+ imagePath = match.match(/src\s*=\s*['"]*([^'">\s]+)['"]*/)?.[1];
61
+ }
62
+ if (imagePath && !imagePath.startsWith('http') && imagePath.includes('/') && !imagePath.includes('authors/')) {
63
+ imagePaths.add(imagePath);
64
+ }
65
+ });
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ scanDirectory(contentDir);
72
+
73
+ // Также добавляем изображения из public/img/examples/ кроме авторов
74
+ const examplesDir = path.join(rootDir, 'public/img/examples');
75
+ if (fs.existsSync(examplesDir)) {
76
+ function addExampleImages(dir, relativePath = '') {
77
+ // Пропускаем папку authors - аватары не нужно обрабатывать
78
+ if (relativePath.includes('authors/')) return;
79
+
80
+ const items = fs.readdirSync(dir);
81
+ for (const item of items) {
82
+ const itemPath = path.join(dir, item);
83
+ const stat = fs.statSync(itemPath);
84
+
85
+ if (stat.isDirectory()) {
86
+ // Пропускаем папку authors
87
+ if (item === 'authors') continue;
88
+ addExampleImages(itemPath, `${relativePath}${item}/`);
89
+ } else if (item.match(/\.(webp|jpg|jpeg|png)$/i) && !dir.includes('previews')) {
90
+ imagePaths.add(`/img/examples/${relativePath}${item}`);
91
+ }
92
+ }
93
+ }
94
+ addExampleImages(examplesDir);
95
+ }
96
+
97
+ return Array.from(imagePaths);
98
+ }
99
+
100
+ // Функция для очистки всех существующих превьюшек
101
+ function cleanupExistingPreviews() {
102
+ const publicDir = path.join(rootDir, 'public');
103
+
104
+ function removePreviewDirs(dir) {
105
+ if (!fs.existsSync(dir)) return;
106
+
107
+ const items = fs.readdirSync(dir);
108
+
109
+ for (const item of items) {
110
+ const itemPath = path.join(dir, item);
111
+ const stat = fs.statSync(itemPath);
112
+
113
+ if (stat.isDirectory()) {
114
+ if (item === 'previews') {
115
+ console.log(`Removing existing preview directory: ${itemPath}`);
116
+ fs.rmSync(itemPath, { recursive: true, force: true });
117
+ } else {
118
+ removePreviewDirs(itemPath);
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ removePreviewDirs(publicDir);
125
+ }
126
+
127
+ // Функция для создания превьюшки
128
+ async function createPreview(imagePath) {
129
+ const fullImagePath = path.join(rootDir, 'public', imagePath.replace(/^\//, ''));
130
+
131
+ if (!fs.existsSync(fullImagePath)) {
132
+ console.warn(`Image not found: ${fullImagePath}`);
133
+ return;
134
+ }
135
+
136
+ const dir = path.dirname(fullImagePath);
137
+ const ext = path.extname(fullImagePath);
138
+ const name = path.basename(fullImagePath, ext);
139
+ const previewPath = path.join(dir, 'previews', `${name}${ext}`);
140
+
141
+ // Создаем папку previews если её нет
142
+ const previewDir = path.dirname(previewPath);
143
+ if (!fs.existsSync(previewDir)) {
144
+ fs.mkdirSync(previewDir, { recursive: true });
145
+ }
146
+
147
+ try {
148
+ await sharp(fullImagePath)
149
+ .resize(previewWidth, previewHeight, { fit: 'cover' })
150
+ .toFile(previewPath);
151
+
152
+ console.log(`Preview created: ${previewPath}`);
153
+ } catch (error) {
154
+ console.error(`Error processing ${fullImagePath}:`, error.message);
155
+ }
156
+ }
157
+
158
+ // Основная функция
159
+ async function generatePreviews() {
160
+ console.log('Cleaning up existing previews...');
161
+ cleanupExistingPreviews();
162
+
163
+ console.log('Scanning content for images...');
164
+ const imagePaths = extractImagePaths();
165
+
166
+ console.log(`Found ${imagePaths.length} images to process`);
167
+
168
+ for (const imagePath of imagePaths) {
169
+ await createPreview(imagePath);
170
+ }
171
+
172
+ console.log('Preview generation completed!');
173
+ }
174
+
175
+ generatePreviews().catch(console.error);
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import { fileURLToPath, pathToFileURL } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ // Определяем корневые папки
11
+ const packageRoot = __dirname.includes('node_modules')
12
+ ? path.join(__dirname, '../../..', 'node_modules', 'core-maugli') // из node_modules
13
+ : path.join(__dirname, '..'); // из исходников (для разработки)
14
+
15
+ const userRoot = __dirname.includes('node_modules')
16
+ ? path.join(__dirname, '../../..') // корень пользовательского проекта
17
+ : process.env.INIT_CWD || process.cwd(); // для разработки
18
+
19
+ // Список папок и файлов для полного обновления (перезаписи)
20
+ const FORCE_UPDATE_PATHS = [
21
+ 'src/components',
22
+ 'src/layouts',
23
+ 'src/pages',
24
+ 'src/utils',
25
+ 'src/scripts',
26
+ 'src/icons',
27
+ 'src/i18n',
28
+ 'public/flags',
29
+ 'public/img/default'
30
+ // Исключили src/styles - может содержать пользовательские стили
31
+ ];
32
+
33
+ // Список файлов, которые НЕ должны перезаписываться (пользовательские)
34
+ const PRESERVE_PATHS = [
35
+ 'src/content',
36
+ 'src/config/maugli.config.ts', // обновляется через upgrade-config.js
37
+ 'src/styles/global.css', // может быть кастомизирован пользователем
38
+ 'package.json',
39
+ 'astro.config.mjs',
40
+ 'tailwind.config.js',
41
+ 'tsconfig.json'
42
+ ];
43
+
44
+ async function copyDirectory(src, dest) {
45
+ try {
46
+ await fs.mkdir(dest, { recursive: true });
47
+
48
+ const entries = await fs.readdir(src, { withFileTypes: true });
49
+
50
+ for (const entry of entries) {
51
+ const srcPath = path.join(src, entry.name);
52
+ const destPath = path.join(dest, entry.name);
53
+
54
+ if (entry.isDirectory()) {
55
+ await copyDirectory(srcPath, destPath);
56
+ } else {
57
+ await fs.copyFile(srcPath, destPath);
58
+ console.log(`Updated: ${path.relative(userRoot, destPath)}`);
59
+ }
60
+ }
61
+ } catch (error) {
62
+ console.warn(`Warning: Could not copy ${src} to ${dest}:`, error.message);
63
+ }
64
+ }
65
+
66
+ async function updateStyles() {
67
+ const srcStylesPath = path.join(packageRoot, 'src/styles');
68
+ const destStylesPath = path.join(userRoot, 'src/styles');
69
+
70
+ try {
71
+ // Проверяем, существует ли папка styles в пакете
72
+ await fs.stat(srcStylesPath);
73
+
74
+ // Проверяем, есть ли уже пользовательские стили
75
+ try {
76
+ const userGlobalCss = path.join(destStylesPath, 'global.css');
77
+ await fs.stat(userGlobalCss);
78
+ console.log('📝 Preserving user styles (global.css exists)');
79
+
80
+ // Копируем только новые файлы стилей, не трогая global.css
81
+ const entries = await fs.readdir(srcStylesPath, { withFileTypes: true });
82
+ await fs.mkdir(destStylesPath, { recursive: true });
83
+
84
+ for (const entry of entries) {
85
+ if (entry.name !== 'global.css') {
86
+ const srcFile = path.join(srcStylesPath, entry.name);
87
+ const destFile = path.join(destStylesPath, entry.name);
88
+ await fs.copyFile(srcFile, destFile);
89
+ console.log(`Updated style: ${entry.name}`);
90
+ }
91
+ }
92
+ } catch {
93
+ // Пользовательских стилей нет, копируем все
94
+ await copyDirectory(srcStylesPath, destStylesPath);
95
+ console.log('📝 Copied default styles');
96
+ }
97
+ } catch (error) {
98
+ console.warn('Warning: Could not update styles:', error.message);
99
+ }
100
+ }
101
+
102
+ async function updateComponents() {
103
+ console.log('🔄 Updating Maugli components and assets...');
104
+
105
+ // Проверяем, что мы не в том же проекте (чтобы не удалить исходники)
106
+ if (packageRoot === userRoot) {
107
+ console.log('⚠️ Skipping component update (running in source project)');
108
+ return;
109
+ }
110
+
111
+ let updatedCount = 0;
112
+
113
+ for (const updatePath of FORCE_UPDATE_PATHS) {
114
+ const srcPath = path.join(packageRoot, updatePath);
115
+ const destPath = path.join(userRoot, updatePath);
116
+
117
+ try {
118
+ // Проверяем, существует ли исходная папка/файл
119
+ const stats = await fs.stat(srcPath);
120
+
121
+ if (stats.isDirectory()) {
122
+ // Удаляем существующую папку и копируем новую
123
+ try {
124
+ await fs.rm(destPath, { recursive: true, force: true });
125
+ } catch (e) {
126
+ // Папки может не быть - это нормально
127
+ }
128
+
129
+ await copyDirectory(srcPath, destPath);
130
+ updatedCount++;
131
+ } else if (stats.isFile()) {
132
+ // Копируем отдельный файл
133
+ await fs.mkdir(path.dirname(destPath), { recursive: true });
134
+ await fs.copyFile(srcPath, destPath);
135
+ console.log(`Updated: ${path.relative(userRoot, destPath)}`);
136
+ updatedCount++;
137
+ }
138
+ } catch (error) {
139
+ if (error.code !== 'ENOENT') {
140
+ console.warn(`Warning: Could not update ${updatePath}:`, error.message);
141
+ }
142
+ }
143
+ }
144
+
145
+ // Обрабатываем стили отдельно
146
+ await updateStyles();
147
+
148
+ console.log(`✅ Updated ${updatedCount} component directories/files`);
149
+ }
150
+
151
+ async function main() {
152
+ try {
153
+ await updateComponents();
154
+ console.log('🎉 Component update completed successfully!');
155
+ } catch (error) {
156
+ console.error('❌ Component update failed:', error);
157
+ process.exit(1);
158
+ }
159
+ }
160
+
161
+ // Запускаем только если вызывается напрямую
162
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
163
+ main();
164
+ }
165
+
166
+ export { updateComponents };
@@ -1,14 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import fs from 'fs/promises';
4
- import path from 'path';
5
4
  import os from 'os';
6
- import { fileURLToPath, pathToFileURL } from 'url';
5
+ import path from 'path';
7
6
  import ts from 'typescript';
7
+ import { fileURLToPath, pathToFileURL } from 'url';
8
8
 
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
11
11
 
12
+ // Импортируем функцию обновления компонентов
13
+ async function importUpdateComponents() {
14
+ try {
15
+ const { updateComponents } = await import('./update-components.js');
16
+ return updateComponents;
17
+ } catch (error) {
18
+ console.warn('Could not load update-components.js:', error.message);
19
+ return null;
20
+ }
21
+ }
22
+
12
23
  const defaultConfigPath = path.join(__dirname, '../src/config/maugli.config.ts');
13
24
  const userRoot = process.env.INIT_CWD || process.cwd();
14
25
  const userConfigPath = path.join(userRoot, 'src/config/maugli.config.ts');
@@ -43,6 +54,15 @@ function mergeMissing(target, source) {
43
54
  }
44
55
 
45
56
  async function main() {
57
+ console.log('🔄 Starting Maugli upgrade process...');
58
+
59
+ // Сначала обновляем компоненты
60
+ const updateComponents = await importUpdateComponents();
61
+ if (updateComponents) {
62
+ await updateComponents();
63
+ }
64
+
65
+ // Затем обновляем конфиг
46
66
  const pkg = await loadTsModule(defaultConfigPath);
47
67
  const defCfg = pkg.maugliConfig;
48
68
  const newVersion = pkg.MAUGLI_CONFIG_VERSION || defCfg.configVersion;
@@ -50,7 +70,7 @@ async function main() {
50
70
  try {
51
71
  await fs.access(userConfigPath);
52
72
  } catch {
53
- console.warn(`User config not found at ${userConfigPath}, skipping upgrade`);
73
+ console.warn(`User config not found at ${userConfigPath}, skipping config upgrade`);
54
74
  return;
55
75
  }
56
76
 
@@ -24,15 +24,7 @@ const current = availableLanguages.find((l) => l.code === currentLang) || availa
24
24
  class="flag-box flex items-center justify-center w-7 h-7 rounded-[var(--radius-main)] shadow-[var(--shadow-main)]"
25
25
  style="min-width:28px; min-height:28px; max-width:28px; max-height:28px;"
26
26
  >
27
- {current && (
28
- <img
29
- src={current.icon.replace(/^\/public\/|^\/|^flags\//, '/src/icons/flags/')}
30
- alt={current.code.toUpperCase()}
31
- width="28"
32
- height="28"
33
- style="pointer-events:none;"
34
- />
35
- )}
27
+ {current && <img src={current.icon} alt={current.code.toUpperCase()} width="28" height="28" style="pointer-events:none;" />}
36
28
  </span>
37
29
  <svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor">
38
30
  <path
@@ -65,13 +57,7 @@ const current = availableLanguages.find((l) => l.code === currentLang) || availa
65
57
  class="flag-box flex items-center justify-center w-7 h-7 rounded-[var(--radius-main)] shadow-[var(--shadow-main)]"
66
58
  style="min-width:28px; min-height:28px; max-width:28px; max-height:28px;"
67
59
  >
68
- <img
69
- src={lang.icon.replace(/^\/public\/|^\/|^flags\//, '/src/icons/flags/')}
70
- alt={lang.code.toUpperCase()}
71
- width="28"
72
- height="28"
73
- style="pointer-events:none;"
74
- />
60
+ <img src={lang.icon} alt={lang.code.toUpperCase()} width="28" height="28" style="pointer-events:none;" />
75
61
  </span>
76
62
  <span class="text-heading">{lang.label}</span>
77
63
  </a>