core-maugli 1.1.7 → 1.1.9

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
@@ -8,14 +8,19 @@ Maugli is a lightweight, agent-friendly blog that can integrate into an existing
8
8
 
9
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
10
 
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)
11
+ [![Deploy to Netlify Button](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/dashapps/core-maugli-blog)
12
12
 
13
- Before deploying, push this project to your own Git repository. Update the
14
- `repository=` parameter in the link above so it points to your repository or
15
- connect the repo through the Netlify UI.
13
+ The Netlify deployment button automatically uses your repository URL configured in [`src/config/maugli.config.ts`](src/config/maugli.config.ts). When you run `npx core-maugli init`, it will ask for your repository URL and configure the deployment button accordingly.
16
14
 
17
- Example link:
18
- `https://app.netlify.com/start/deploy?repository=https://github.com/your-user/your-repo`
15
+ You can also use the dynamic `<NetlifyButton />` component in your Astro pages:
16
+
17
+ ```astro
18
+ ---
19
+ import NetlifyButton from '../components/NetlifyButton.astro';
20
+ ---
21
+
22
+ <NetlifyButton />
23
+ ```
19
24
 
20
25
  Using Netlify CLI instead:
21
26
 
@@ -239,3 +244,4 @@ commercial license.
239
244
 
240
245
  Contact <licensing@maugli.cfd> or visit
241
246
  <https://maugli.cfd/licensing> for more information.
247
+
package/bin/init.js CHANGED
@@ -31,7 +31,47 @@ function promptLang(codes) {
31
31
  });
32
32
  }
33
33
 
34
- function updateConfig(targetDir, lang) {
34
+ function promptRepo() {
35
+ return new Promise(resolve => {
36
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
37
+ rl.question('Repository URL: ', answer => {
38
+ rl.close();
39
+ resolve(answer.trim());
40
+ });
41
+ });
42
+ }
43
+
44
+ async function getRepoUrl(targetDir, repoOption) {
45
+ if (repoOption) return repoOption;
46
+ try {
47
+ const url = execSync('git remote get-url origin', {
48
+ cwd: targetDir,
49
+ stdio: ['ignore', 'pipe', 'ignore']
50
+ })
51
+ .toString()
52
+ .trim();
53
+ if (url) return url;
54
+ } catch {
55
+ // ignore
56
+ }
57
+ return await promptRepo();
58
+ }
59
+
60
+ function updateReadme(targetDir, repoUrl) {
61
+ if (!repoUrl) return;
62
+ const readmePath = path.join(targetDir, 'README.md');
63
+ if (!existsSync(readmePath)) return;
64
+ let content = readFileSync(readmePath, 'utf8');
65
+ const pattern = /https:\/\/app\.netlify\.com\/start\/deploy\?repository=[^\)\s]+/;
66
+ content = content.replace(
67
+ pattern,
68
+ `https://app.netlify.com/start/deploy?repository=${repoUrl}`
69
+ );
70
+ writeFileSync(readmePath, content);
71
+ console.log('Updated Netlify link in README.md');
72
+ }
73
+
74
+ function updateConfig(targetDir, lang, repoUrl) {
35
75
  const configPath = path.join(targetDir, 'src', 'config', 'maugli.config.ts');
36
76
  if (!existsSync(configPath)) return;
37
77
  let content = readFileSync(configPath, 'utf8');
@@ -39,11 +79,23 @@ function updateConfig(targetDir, lang) {
39
79
  const multiMatch = content.match(/enableMultiLang:\s*(true|false)/);
40
80
  const multi = multiMatch ? multiMatch[1] === 'true' : false;
41
81
  content = content.replace(/showLangSwitcher:\s*(true|false)/, `showLangSwitcher: ${multi}`);
82
+
83
+ // Update repository URL if provided
84
+ if (repoUrl) {
85
+ content = content.replace(
86
+ /repository:\s*{[^}]*url:\s*'[^']*'/,
87
+ `repository: {\n url: '${repoUrl}'`
88
+ );
89
+ }
90
+
42
91
  writeFileSync(configPath, content);
43
92
  console.log(`Configured default language to ${lang}`);
93
+ if (repoUrl) {
94
+ console.log(`Configured repository URL to ${repoUrl}`);
95
+ }
44
96
  }
45
97
 
46
- export default async function init(targetName, langOption) {
98
+ export default async function init(targetName, langOption, repoOption) {
47
99
  const targetDir = targetName ? path.resolve(targetName) : process.cwd();
48
100
  const codes = getLanguageCodes();
49
101
  const lang = langOption && codes.includes(langOption) ? langOption : await promptLang(codes);
@@ -82,6 +134,9 @@ export default async function init(targetName, langOption) {
82
134
  ];
83
135
  items.forEach(copyItem);
84
136
 
137
+ const repoUrl = await getRepoUrl(targetDir, repoOption);
138
+ updateReadme(targetDir, repoUrl);
139
+
85
140
  // Create essential config files
86
141
  const gitignoreContent = `
87
142
  # Dependencies
@@ -122,7 +177,7 @@ dist/
122
177
  console.log('Created .prettierrc');
123
178
 
124
179
  execSync('npm install', { cwd: targetDir, stdio: 'inherit' });
125
- updateConfig(targetDir, lang);
180
+ updateConfig(targetDir, lang, repoUrl);
126
181
  }
127
182
 
128
183
  // Если скрипт запускается напрямую
@@ -130,13 +185,17 @@ if (import.meta.url === `file://${process.argv[1]}`) {
130
185
  const args = process.argv.slice(2);
131
186
  let targetName;
132
187
  let lang;
188
+ let repo;
133
189
  for (let i = 0; i < args.length; i++) {
134
190
  if (args[i] === '--lang' && i + 1 < args.length) {
135
191
  lang = args[i + 1];
136
192
  i++;
193
+ } else if (args[i] === '--repo' && i + 1 < args.length) {
194
+ repo = args[i + 1];
195
+ i++;
137
196
  } else {
138
197
  targetName = args[i];
139
198
  }
140
199
  }
141
- await init(targetName, lang);
142
- }
200
+ await init(targetName, lang, repo);
201
+ }
package/package.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "name": "core-maugli",
3
3
  "description": "Astro & Tailwind CSS blog theme for Maugli.",
4
4
  "type": "module",
5
- "version": "1.1.7",
5
+ "version": "1.1.9",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/dashapps/maugli-astro-theme.git"
9
+ "url": "git+https://github.com/dashapps/core-maugli-blog.git"
10
10
  },
11
11
  "author": "Maugli Content Farm",
12
12
  "keywords": [
@@ -10,81 +10,89 @@ const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
11
11
 
12
12
  const defaultConfigPath = path.join(__dirname, '../src/config/maugli.config.ts');
13
- const userConfigPath = path.join(process.cwd(), 'src/config/maugli.config.ts');
13
+ const userRoot = process.env.INIT_CWD || process.cwd();
14
+ const userConfigPath = path.join(userRoot, 'src/config/maugli.config.ts');
14
15
 
15
16
  async function loadTsModule(filePath) {
16
- const code = await fs.readFile(filePath, 'utf8');
17
- const js = ts.transpileModule(code, {
18
- compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2020 }
19
- }).outputText;
20
- const tmp = path.join(os.tmpdir(), `maugli-${Date.now()}.mjs`);
21
- await fs.writeFile(tmp, js, 'utf8');
22
- const mod = await import(pathToFileURL(tmp).href);
23
- await fs.unlink(tmp);
24
- return mod;
17
+ const code = await fs.readFile(filePath, 'utf8');
18
+ const js = ts.transpileModule(code, {
19
+ compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2020 }
20
+ }).outputText;
21
+ const tmp = path.join(os.tmpdir(), `maugli-${Date.now()}.mjs`);
22
+ await fs.writeFile(tmp, js, 'utf8');
23
+ const mod = await import(pathToFileURL(tmp).href);
24
+ await fs.unlink(tmp);
25
+ return mod;
25
26
  }
26
27
 
27
28
  function mergeMissing(target, source) {
28
- for (const key of Object.keys(source)) {
29
- if (key === 'configVersion') continue;
30
- const sv = source[key];
31
- const tv = target[key];
32
- if (sv && typeof sv === 'object' && !Array.isArray(sv)) {
33
- if (!tv || typeof tv !== 'object' || Array.isArray(tv)) {
34
- if (!(key in target)) target[key] = sv;
35
- } else {
36
- mergeMissing(tv, sv);
37
- }
38
- } else {
39
- if (!(key in target)) target[key] = sv;
29
+ for (const key of Object.keys(source)) {
30
+ if (key === 'configVersion') continue;
31
+ const sv = source[key];
32
+ const tv = target[key];
33
+ if (sv && typeof sv === 'object' && !Array.isArray(sv)) {
34
+ if (!tv || typeof tv !== 'object' || Array.isArray(tv)) {
35
+ if (!(key in target)) target[key] = sv;
36
+ } else {
37
+ mergeMissing(tv, sv);
38
+ }
39
+ } else {
40
+ if (!(key in target)) target[key] = sv;
41
+ }
40
42
  }
41
- }
42
43
  }
43
44
 
44
45
  async function main() {
45
- const pkg = await loadTsModule(defaultConfigPath);
46
- const defCfg = pkg.maugliConfig;
47
- const newVersion = pkg.MAUGLI_CONFIG_VERSION || defCfg.configVersion;
46
+ const pkg = await loadTsModule(defaultConfigPath);
47
+ const defCfg = pkg.maugliConfig;
48
+ const newVersion = pkg.MAUGLI_CONFIG_VERSION || defCfg.configVersion;
48
49
 
49
- let user;
50
- try {
51
- user = await loadTsModule(userConfigPath);
52
- } catch (err) {
53
- console.error(`Cannot find user config at ${userConfigPath}`);
54
- process.exit(1);
55
- }
56
- const userCfg = user.maugliConfig;
57
- if (userCfg.configVersion === newVersion) {
58
- console.log('maugli.config.ts is already up to date');
59
- return;
60
- }
50
+ try {
51
+ await fs.access(userConfigPath);
52
+ } catch {
53
+ console.warn(`User config not found at ${userConfigPath}, skipping upgrade`);
54
+ return;
55
+ }
56
+
57
+ let user;
58
+ try {
59
+ user = await loadTsModule(userConfigPath);
60
+ } catch (err) {
61
+ console.warn(`Cannot load user config at ${userConfigPath}:`, err.message);
62
+ return;
63
+ }
64
+ const userCfg = user.maugliConfig;
65
+ if (userCfg.configVersion === newVersion) {
66
+ console.log('maugli.config.ts is already up to date');
67
+ return;
68
+ }
61
69
 
62
- mergeMissing(userCfg, defCfg);
63
- userCfg.configVersion = newVersion;
70
+ mergeMissing(userCfg, defCfg);
71
+ userCfg.configVersion = newVersion;
64
72
 
65
- const defText = await fs.readFile(defaultConfigPath, 'utf8');
66
- const headerEnd = defText.indexOf('export const maugliConfig');
67
- let header = defText.slice(0, headerEnd);
68
- header = header.replace(/MAUGLI_CONFIG_VERSION\s*=\s*['\"][^'\"]*['\"]/, `MAUGLI_CONFIG_VERSION = '${newVersion}'`);
69
- let bracePos = defText.indexOf('{', headerEnd);
70
- let count = 0, i = bracePos;
71
- for (; i < defText.length; i++) {
72
- if (defText[i] === '{') count++;
73
- else if (defText[i] === '}') count--;
74
- if (count === 0) break;
75
- }
76
- let j = i;
77
- while (j < defText.length && defText[j] !== ';') j++;
78
- const tail = defText.slice(j + 1);
73
+ const defText = await fs.readFile(defaultConfigPath, 'utf8');
74
+ const headerEnd = defText.indexOf('export const maugliConfig');
75
+ let header = defText.slice(0, headerEnd);
76
+ header = header.replace(/MAUGLI_CONFIG_VERSION\s*=\s*['\"][^'\"]*['\"]/, `MAUGLI_CONFIG_VERSION = '${newVersion}'`);
77
+ let bracePos = defText.indexOf('{', headerEnd);
78
+ let count = 0,
79
+ i = bracePos;
80
+ for (; i < defText.length; i++) {
81
+ if (defText[i] === '{') count++;
82
+ else if (defText[i] === '}') count--;
83
+ if (count === 0) break;
84
+ }
85
+ let j = i;
86
+ while (j < defText.length && defText[j] !== ';') j++;
87
+ const tail = defText.slice(j + 1);
79
88
 
80
- const newObject = JSON.stringify(userCfg, null, 2);
81
- const result = `${header}export const maugliConfig: MaugliConfig = ${newObject};${tail}`;
82
- await fs.writeFile(userConfigPath, result, 'utf8');
83
- console.log(`Upgraded maugli.config.ts to version ${newVersion}`);
89
+ const newObject = JSON.stringify(userCfg, null, 2);
90
+ const result = `${header}export const maugliConfig: MaugliConfig = ${newObject};${tail}`;
91
+ await fs.writeFile(userConfigPath, result, 'utf8');
92
+ console.log(`Upgraded maugli.config.ts to version ${newVersion}`);
84
93
  }
85
94
 
86
- main().catch(err => {
87
- console.error('Upgrade failed:', err);
88
- process.exit(1);
95
+ main().catch((err) => {
96
+ console.error('Upgrade failed:', err);
97
+ process.exit(1);
89
98
  });
90
-
@@ -0,0 +1,22 @@
1
+ ---
2
+ import { maugliConfig } from '../config/maugli.config.ts';
3
+
4
+ interface Props {
5
+ class?: string;
6
+ }
7
+
8
+ const { class: className } = Astro.props;
9
+
10
+ // Use repository URL from config, fallback to default
11
+ const repositoryUrl = maugliConfig.repository?.url || 'https://github.com/dashapps/core-maugli-blog';
12
+ const netlifyEnabled = maugliConfig.repository?.netlifyEnabled !== false;
13
+ const netlifyUrl = `https://app.netlify.com/start/deploy?repository=${repositoryUrl}`;
14
+ ---
15
+
16
+ {
17
+ netlifyEnabled && (
18
+ <a href={netlifyUrl} target="_blank" rel="noopener noreferrer" class={className}>
19
+ <img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify" />
20
+ </a>
21
+ )
22
+ }
@@ -1,5 +1,5 @@
1
1
  // MAUGLI_CONFIG_VERSION — config version for CLI/automation compatibility
2
- export const MAUGLI_CONFIG_VERSION = '0.2';
2
+ export const MAUGLI_CONFIG_VERSION = '0.3';
3
3
  // Main configuration interface for the Maugli project
4
4
  export interface MaugliConfig {
5
5
  // Show example/demo content (for CLI/empty blog setup)
@@ -19,6 +19,11 @@ export interface MaugliConfig {
19
19
  farmProductIds?: string[]; // Array of farm product IDs for API
20
20
  farmProjectIds?: string[]; // Array of farm project/case IDs for API
21
21
  };
22
+ // Repository settings for deployment
23
+ repository?: {
24
+ url?: string; // User's repository URL for Netlify deployment button
25
+ netlifyEnabled?: boolean; // Enable Netlify deployment button (default: true)
26
+ };
22
27
  // Brand and logo settings
23
28
  brand: {
24
29
  name: string; // Brand name
@@ -111,6 +116,11 @@ export const maugliConfig: MaugliConfig = {
111
116
  farmProductIds: [], // Array of farm product IDs for API
112
117
  farmProjectIds: [], // Array of farm project/case IDs for API
113
118
  },
119
+ // Repository settings for deployment
120
+ repository: {
121
+ url: 'https://github.com/dashapps/core-maugli-blog', // User's repository URL for Netlify deployment button
122
+ netlifyEnabled: true, // Enable Netlify deployment button (default: true)
123
+ },
114
124
  enableThemeSwitcher: true, // Enable theme switcher (true by default)
115
125
  seo: {
116
126
  titleSuffix: ' — Maugli', // Suffix for page titles