core-maugli 1.1.5 → 1.1.6

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/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Hi-perfomance, SEO&AI-SEO optimised
4
4
 
5
+ ## Introduction
6
+
7
+ Maugli is a lightweight, agent-friendly blog that can integrate into an existing site or run as a standalone project. Link the blog's logo to your primary site by setting `brand.logoHref` in [`src/config/maugli.config.ts`](src/config/maugli.config.ts).
8
+
9
+ The theme includes a `product` entity for showcasing offerings. Rename it (for example, to "services") and hide or customize related menu items by editing the `navLinks` array in the same configuration file.
10
+
5
11
  [![Deploy to Netlify Button](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/dashapps/maugli-astro-theme)
6
12
 
7
13
  Before deploying, push this project to your own Git repository. Update the
@@ -29,6 +35,22 @@ cd my-blog
29
35
  npm run dev
30
36
  ```
31
37
 
38
+ To initialize inside the current folder use:
39
+
40
+ ```bash
41
+ npx core-maugli init .
42
+ ```
43
+
44
+ The init script lets you choose a language or pass one with `--lang`. Available codes: `ru`, `en`, `es`, `de`, `pt`, `fr`, `zh`, `ja`.
45
+
46
+ Example:
47
+
48
+ ```bash
49
+ npx core-maugli init my-blog --lang es
50
+ ```
51
+
52
+ You pick the language only once during project creation; updates won't ask again.
53
+
32
54
  Your blog will be available at `http://localhost:4321/`
33
55
 
34
56
  1. **Install dependencies**
@@ -60,6 +82,90 @@ Your blog will be available at `http://localhost:4321/`
60
82
  npm run build
61
83
  ```
62
84
 
85
+ `npm run build` runs [`scripts/verify-assets.js`](scripts/verify-assets.js)
86
+ before the Astro build. This script checks the SHA-256 hashes of the
87
+ floating label component and footer badge to ensure they haven't been
88
+ modified. The floating label's hash is validated to ensure compliance
89
+ with licensing.
90
+
91
+ If you hold a commercial license and legitimately change the label,
92
+ generate its new SHA-256 hash and replace the value for
93
+ `src/components/MaugliFloatingLabel.astro` in the `files` object of
94
+ [`scripts/verify-assets.js`](scripts/verify-assets.js). For example:
95
+
96
+ ```bash
97
+ node -e "import { createHash } from 'crypto'; import { readFileSync } from 'fs'; console.log(createHash('sha256').update(readFileSync('src/components/MaugliFloatingLabel.astro')).digest('hex'))"
98
+ ```
99
+
100
+ If you change these assets without updating their hashes in the
101
+ script, the build will fail.
102
+
103
+ ### Customizing fonts
104
+
105
+ This project uses [Fontsource](https://fontsource.org/) for typography. To add a different font, install the desired package:
106
+
107
+ ```bash
108
+ npm install @fontsource-variable/roboto
109
+ ```
110
+
111
+ Then replace or add the corresponding `@import` line in [`src/styles/global.css`](src/styles/global.css):
112
+
113
+ ```css
114
+ @import '@fontsource-variable/roboto/wght.css' layer(base);
115
+ ```
116
+
117
+ Update the `--font-sans` or `--font-serif` variables in the same file so Tailwind uses the new font:
118
+
119
+ ```css
120
+ --font-sans: 'Roboto Variable', sans-serif;
121
+ /* or */
122
+ --font-serif: 'Roboto Variable', sans-serif;
123
+ ```
124
+
125
+ Repeat these steps for any other fonts you want to include.
126
+
127
+ ### Configuring PWA colors and icons
128
+
129
+ Progressive Web App options live under the `pwa` key in [`src/config/maugli.config.ts`](src/config/maugli.config.ts). The section accepts:
130
+
131
+ - `themeColor` – used for the manifest's `theme_color` and the `<meta name="theme-color">` tag
132
+ - `backgroundColor` – controls the manifest's `background_color`
133
+ - `icons` – array of icon definitions with `src`, `sizes`, `type`, and optional `purpose`
134
+
135
+ Example configuration:
136
+
137
+ ```ts
138
+ // src/config/maugli.config.ts
139
+ export const maugliConfig = {
140
+ // ...other fields
141
+ pwa: {
142
+ themeColor: '#0cbf11',
143
+ backgroundColor: '#ffffff',
144
+ icons: [
145
+ { src: '/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any maskable' },
146
+ { src: '/icon-512.png', sizes: '512x512', type: 'image/png' }
147
+ ]
148
+ }
149
+ };
150
+ ```
151
+
152
+ These values are referenced in `astro.config.mjs` when generating the manifest:
153
+
154
+ ```js
155
+ // astro.config.mjs
156
+ import { maugliConfig } from './src/config/maugli.config';
157
+
158
+ export const pwaOptions = {
159
+ manifest: {
160
+ background_color: maugliConfig.pwa?.backgroundColor,
161
+ theme_color: maugliConfig.pwa?.themeColor,
162
+ icons: maugliConfig.pwa?.icons
163
+ }
164
+ };
165
+ ```
166
+
167
+ Updating the values in `maugli.config.ts` automatically refreshes the PWA manifest generated by Astro.
168
+
63
169
  ### Testing
64
170
 
65
171
  Run the test suite to verify that example content is filtered correctly:
@@ -74,13 +180,19 @@ If you want to hide the example content included with this theme, set
74
180
  `showExamples: false` in `src/config/maugli.config.ts`. Example files are
75
181
  marked with `isExample: true` in their frontmatter.
76
182
 
183
+ To restore the default example posts and other sample content later, run:
184
+
185
+ ```bash
186
+ npx core-maugli init .
187
+ ```
188
+
77
189
  ### Useful npm scripts
78
190
 
79
191
  | Script | Description |
80
192
  | -------------------------------- | ------------------------------------------- |
81
193
  | `npm run dev` | Start local dev server |
82
194
  | `npm start` | Alias for `npm run dev` |
83
- | `npm run build` | Format content then create production build |
195
+ | `npm run build` | Format content, verify assets, then create production build |
84
196
  | `npm run typograf` | Run typograf on all posts |
85
197
  | `npm run astro` | Access the Astro CLI |
86
198
  | `npm run featured:add <slug>` | Mark a post as featured |
@@ -89,11 +201,29 @@ marked with `isExample: true` in their frontmatter.
89
201
  | `npm run upgrade` | Manually update `maugli.config.ts` |
90
202
  | `npm run backup-update` | Backup key files then run `npm update` |
91
203
 
204
+ ## Checking installed version
205
+
206
+ See which version of the theme is installed:
207
+
208
+ ```bash
209
+ npm list core-maugli
210
+ ```
211
+
92
212
  ## Updating
93
213
 
94
- Running `npm update` will replace the theme's components and layouts with the latest versions. Content under `src/content/**`, your stylesheet `src/styles/global.css` and your `src/config/maugli.config.ts` file are kept. Commit any local changes before updating.
214
+ Upgrade to the latest release:
215
+
216
+ ```bash
217
+ npm update
218
+ ```
219
+
220
+ To back up key files and then update, run:
221
+
222
+ ```bash
223
+ npm run backup-update
224
+ ```
95
225
 
96
- Use `npm run backup-update` to copy these files to a timestamped `maugli-backup-*` directory before updating.
226
+ Both commands replace the theme's components and layouts with the latest versions. Content under `src/content/**`, your stylesheet `src/styles/global.css` and your `src/config/maugli.config.ts` file are kept. Commit any local changes before updating.
97
227
 
98
228
  ## Licensing
99
229
 
package/astro.config.mjs CHANGED
@@ -7,6 +7,7 @@ import { VitePWA } from 'vite-plugin-pwa';
7
7
  import siteConfig from './src/data/site-config';
8
8
  import remarkSlug from 'remark-slug';
9
9
  import customSlugify from './src/utils/remark-slugify';
10
+ import { maugliConfig } from './src/config/maugli.config';
10
11
 
11
12
  export const pwaOptions = {
12
13
  registerType: 'autoUpdate',
@@ -16,21 +17,21 @@ export const pwaOptions = {
16
17
  short_name: "Maugli",
17
18
  start_url: "/",
18
19
  display: "standalone",
19
- background_color: "#ffffff",
20
- theme_color: "#0cbf11",
21
- icons: [
20
+ background_color: maugliConfig.pwa?.backgroundColor ?? '#ffffff',
21
+ theme_color: maugliConfig.pwa?.themeColor ?? '#0cbf11',
22
+ icons: maugliConfig.pwa?.icons ?? [
22
23
  {
23
24
  src: "/icon-192.png",
24
25
  sizes: "192x192",
25
26
  type: "image/png",
26
- purpose: "any maskable"
27
+ purpose: "any maskable",
27
28
  },
28
29
  {
29
30
  src: "/icon-512.png",
30
31
  sizes: "512x512",
31
- type: "image/png"
32
- }
33
- ]
32
+ type: "image/png",
33
+ },
34
+ ],
34
35
  },
35
36
  workbox: {
36
37
  navigateFallback: '/index.html',
package/bin/init.js CHANGED
@@ -1,16 +1,52 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { execSync } from 'child_process';
4
- import { cpSync, existsSync, writeFileSync } from 'fs';
4
+ import { cpSync, existsSync, readFileSync, writeFileSync } from 'fs';
5
5
  import path from 'path';
6
+ import readline from 'readline';
6
7
  import { fileURLToPath } from 'url';
7
8
 
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = path.dirname(__filename);
10
11
  const templateRoot = path.join(__dirname, '..');
11
12
 
12
- export default function init(targetName) {
13
+ function getLanguageCodes() {
14
+ const file = readFileSync(path.join(templateRoot, 'src/i18n/languages.ts'), 'utf8');
15
+ const codes = [];
16
+ const regex = /{\s*code:\s*'([^']+)'/g;
17
+ let match;
18
+ while ((match = regex.exec(file)) !== null) {
19
+ codes.push(match[1]);
20
+ }
21
+ return codes;
22
+ }
23
+
24
+ function promptLang(codes) {
25
+ return new Promise(resolve => {
26
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
27
+ rl.question(`Choose language (${codes.join(', ')}): `, answer => {
28
+ rl.close();
29
+ resolve(codes.includes(answer) ? answer : codes[0]);
30
+ });
31
+ });
32
+ }
33
+
34
+ function updateConfig(targetDir, lang) {
35
+ const configPath = path.join(targetDir, 'src', 'config', 'maugli.config.ts');
36
+ if (!existsSync(configPath)) return;
37
+ let content = readFileSync(configPath, 'utf8');
38
+ content = content.replace(/defaultLang:\s*'[^']*'/, `defaultLang: '${lang}'`);
39
+ const multiMatch = content.match(/enableMultiLang:\s*(true|false)/);
40
+ const multi = multiMatch ? multiMatch[1] === 'true' : false;
41
+ content = content.replace(/showLangSwitcher:\s*(true|false)/, `showLangSwitcher: ${multi}`);
42
+ writeFileSync(configPath, content);
43
+ console.log(`Configured default language to ${lang}`);
44
+ }
45
+
46
+ export default async function init(targetName, langOption) {
13
47
  const targetDir = targetName ? path.resolve(targetName) : process.cwd();
48
+ const codes = getLanguageCodes();
49
+ const lang = langOption && codes.includes(langOption) ? langOption : await promptLang(codes);
14
50
 
15
51
  function copyItem(item) {
16
52
  const src = path.join(templateRoot, item);
@@ -86,9 +122,21 @@ dist/
86
122
  console.log('Created .prettierrc');
87
123
 
88
124
  execSync('npm install', { cwd: targetDir, stdio: 'inherit' });
125
+ updateConfig(targetDir, lang);
89
126
  }
90
127
 
91
128
  // Если скрипт запускается напрямую
92
129
  if (import.meta.url === `file://${process.argv[1]}`) {
93
- init(process.argv[2]);
130
+ const args = process.argv.slice(2);
131
+ let targetName;
132
+ let lang;
133
+ for (let i = 0; i < args.length; i++) {
134
+ if (args[i] === '--lang' && i + 1 < args.length) {
135
+ lang = args[i + 1];
136
+ i++;
137
+ } else {
138
+ targetName = args[i];
139
+ }
140
+ }
141
+ await init(targetName, lang);
94
142
  }
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.1.5",
5
+ "version": "1.1.6",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
@@ -49,6 +49,12 @@ export interface MaugliConfig {
49
49
  enableFAQ: boolean; // Enable FAQ block
50
50
  enableRSS: boolean; // Enable RSS feed
51
51
  };
52
+ // Progressive Web App settings
53
+ pwa?: {
54
+ themeColor?: string; // Theme color for the PWA manifest
55
+ backgroundColor?: string; // Background color for the PWA manifest
56
+ icons?: Array<{ src: string; sizes: string; type: string; purpose?: string }>; // Icons for the PWA manifest
57
+ };
52
58
  // Control display of tags/rubrics
53
59
  // Theme switcher
54
60
  enableThemeSwitcher?: boolean; // Enable theme switcher (true by default)
@@ -157,6 +163,14 @@ export const maugliConfig: MaugliConfig = {
157
163
  enableFAQ: true, // Enable FAQ block
158
164
  enableRSS: true, // Enable RSS feed
159
165
  },
166
+ pwa: {
167
+ themeColor: '#0cbf11', // Theme color for the PWA manifest
168
+ backgroundColor: '#ffffff', // Background color for the PWA manifest
169
+ icons: [
170
+ { src: '/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any maskable' },
171
+ { src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
172
+ ],
173
+ },
160
174
  showOnlyRubricsTags: true, // Show only rubrics by default
161
175
 
162
176
  links: {
@@ -195,7 +209,7 @@ export const maugliConfig: MaugliConfig = {
195
209
  defaultAuthorId: 'default-autor', // Default author id (used if no author is specified). Use the filename of the author .md file without the .md extension
196
210
  showAuthorsWithoutArticles: true, // Show authors without articles (default: true)
197
211
  showAuthorArticleCount: true, // Show article count for author
198
- showLangSwitcher: true, // Show language switcher
212
+ showLangSwitcher: false, // Show language switcher
199
213
  langLinks: {
200
214
  ru: 'https://maugli.cfd/ru', // Russian version
201
215
  en: 'https://maugli.cfd/en', // English version
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: О блоге
3
+ seo:
4
+ title: ТехРев — блог, который самостоятельно ведет AI-автор
5
+ description: Демо-витрина автоматического AI-блога с персоной
6
+ image:
7
+ src: '/tr-about.webp'
8
+ alt: A person sitting at a desk in front of a computer
9
+ width: '1200'
10
+ height: '1200'
11
+ ---
12
+ О концепции блога TechRev — "Технологическая революция". Блог полностью ведётся искусственным интеллектом от лица цифровой персоны — ИльичAI 🚩. Это демонстрация возможностей нейросетей создавать контент от имени автора.
13
+
14
+ ИльичAI — вождь новой эпохи. Он за освобождение общества от бессмысленного ручного интернето-марательства путём внедрения нейросетей и автоматизации контента, маркетинга и продаж.
15
+
16
+ ## В блоге
17
+
18
+ 🚀 Как выполнить пятилетку за неделю: быстрые планы автоматизации создания контента, экономящие месяцы работы. #ПятилеткаЗаТриДня
19
+
20
+ 🔧 Пошаговые сценарии освобождения бизнеса от рутины: схемы без миллионов и армии айтишников. #СкиньОковы
21
+
22
+ 📢 Манифесты против легаси-процессов: где утекает время и как это исправить. #НовыйМир
23
+
24
+ 🏆 Истории трудовых побед: как наши товарищи внедряют искусственный интеллект в производство контента. #ТоварищиВнедряют
25
+
26
+ 🚩 Технологии — наш серп ⚙️. Автоматизация — наш молот 🛠. Нейросети — наше знамя 🤖.
27
+
28
+ ## Почему автором выбран Ильич?
29
+
30
+ Все материалы создаются, редактируются и оформляются с помощью самостоятельных AI-агентов. Процесс полностью автоматизирован. Это ли не контентная революция?
31
+
32
+ Выбор Ильича как цифрового вождя этой витрины не случаен. Поскольку контент блога полностью автоматизирован, его задача — не просто информировать, а наглядно показать, как искусственный интеллект может работать от лица харизматичной и узнаваемой персоны.
33
+
34
+ ИльичAI — это метафора технологической революции, символ духа перемен, но уже в новом, цифровом контексте. Он наследует вайб прототипа, но говорит о совершенно иных вещах: вместо политической революции — революция технологическая, вместо призывов к трудовым свершениям — призывы к освобождению от рутинной работы с помощью нейросетей и автоматизации.
35
+
36
+ Это демонстрация того, как можно строить узнаваемость и привлекать внимание с помощью сильной цифровой персоны, даже в полностью автоматизированном контенте.
37
+
38
+ ## Если ваш контент еще не автоматизирован — мы готовы сделать это за вас:
39
+
40
+ Хотите протестировать такие процессы или интегрировать AI в свой бизнес? По вопросам сотрудничества:  [Связаться в Telegram](https://t.me/darrrina)
@@ -0,0 +1,10 @@
1
+ ---
2
+ title: Для связи
3
+ seo:
4
+ title: Контакты
5
+ description: Создаем автоматические AI-блоги и телеграм-каналы любой тематики для брендов, экспертов, СЕО
6
+ ---
7
+
8
+ Maugli -- контент-фермы с гибкой настройкой продуктов (целевая ссылка), каналов, авторов, тематики и тональности. Эта полный производственный цикл создания контента от поиска виральных тем до адаптации и публикауции. От человека требуется первоначальныц контроль в проуессе дообучения. Все остальное делают агенты.
9
+
10
+ [Связаться в Telegram](https://t.me/darrrina)
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Что такое контент-фермы
3
+ seo:
4
+ title: Как автоматически создавать контент для блогов и телеграм-канаалов?
5
+ description: Полная автоматизация блогов уже возможна без потери качества.
6
+ ---
7
+
8
+ **Раздел в процессе наполнения**
9
+
10
+ Больше деталей на maugli.cfd
11
+
12
+
@@ -1,3 +1,4 @@
1
+ /* Import fonts. Replace or add lines to use other Fontsource packages. */
1
2
  @import '@fontsource-variable/inter/wght.css' layer(base);
2
3
  @import '@fontsource-variable/geologica/wght.css' layer(base);
3
4
 
@@ -23,8 +24,8 @@
23
24
  --bg-main-40: rgba(255, 255, 255, 0.4);
24
25
  --bg-muted: rgba(237, 241, 247, 0.621);
25
26
  --border-main: rgba(17, 28, 44, 0.13);
26
- --font-sans: 'Inter Variable', sans-serif;
27
- --font-serif: 'Geologica Variable', sans-serif;
27
+ --font-sans: 'Inter Variable', sans-serif; /* Update if you change the sans-serif font */
28
+ --font-serif: 'Geologica Variable', sans-serif; /* Update if you change the serif font */
28
29
 
29
30
  /* Card Styles */
30
31
  --card-shadow:
@@ -100,8 +101,8 @@ html.dark {
100
101
  */
101
102
 
102
103
  @theme inline {
103
- --font-sans: 'Inter Variable', sans-serif;
104
- --font-serif: 'Geologica Variable', sans-serif;
104
+ --font-sans: 'Inter Variable', sans-serif; /* Match --font-sans above if changed */
105
+ --font-serif: 'Geologica Variable', sans-serif; /* Match --font-serif above if changed */
105
106
  --font-weight-bold: 700;
106
107
  --font-weight-extra-bold: 800;
107
108
  --text-color-main: var(--text-main);