ultimate-jekyll-manager 1.6.2 → 1.6.3
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/CHANGELOG.md +17 -0
- package/CLAUDE.md +1 -1
- package/assets/icons/flags/modern-square/id.svg +1 -0
- package/assets/icons/flags/modern-square/in.svg +1 -0
- package/assets/icons/flags/modern-square/ph.svg +1 -0
- package/assets/icons/flags/modern-square/pk.svg +1 -0
- package/assets/icons/flags/modern-square/ru.svg +1 -0
- package/assets/icons/flags/modern-square/vn.svg +1 -0
- package/dist/commands/setup.js +50 -20
- package/dist/defaults/.github/workflows/build.yml +1 -2
- package/dist/gulp/tasks/defaults.js +14 -1
- package/dist/gulp/tasks/webpack.js +4 -1
- package/docs/icons.md +15 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
14
14
|
- `Fixed` for any bug fixes.
|
|
15
15
|
- `Security` in case of vulnerabilities.
|
|
16
16
|
|
|
17
|
+
---
|
|
18
|
+
## [1.6.3] - 2026-06-03
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Workflow template dynamically generates secrets from `.env`.** `defaults.js` reads the default `_.env`, extracts all key names, and produces a `{ github.secrets }` template variable — no more hardcoding individual secrets in `build.yml`.
|
|
23
|
+
- **`publishSecrets()` replaces `publishGitHubToken()` in setup.** Now reads the consumer's `.env` and publishes ALL non-empty keys as GitHub Actions repo secrets (not just `GH_TOKEN`).
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **Country flag SVGs:** id, in, ph, pk, ru, vn (modern-square style).
|
|
28
|
+
- **Auto-create `pages/` dir for custom themes** in webpack.js — prevents `Module not found: __theme__/pages` error when a consumer theme lacks a `pages/` directory.
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- **`BACKEND_MANAGER_KEY`** removed from workflow template (replaced by dynamic `.env` secrets).
|
|
33
|
+
|
|
17
34
|
---
|
|
18
35
|
## [1.6.2] - 2026-06-02
|
|
19
36
|
|
package/CLAUDE.md
CHANGED
|
@@ -200,7 +200,7 @@ Deep references live in `docs/`. Treat docs as a first-class deliverable. **When
|
|
|
200
200
|
- [docs/themes.md](docs/themes.md) — theme system: selection + resolution (SCSS loadPaths, `__theme__`, classy layout fallback), shared vs per-theme layers, authoring a theme inside UJM OR in a consumer project, live validation
|
|
201
201
|
- [docs/layouts-and-pages.md](docs/layouts-and-pages.md) — page types, layout chain, `asset_path` frontmatter
|
|
202
202
|
- [docs/images.md](docs/images.md) — `@post/` shortcut for blog post images, BEM admin/post image handling, imagemin pipeline + source-size constraints + `UJ_IMAGEMIN_REWRITE_SOURCES` cleanup flag
|
|
203
|
-
- [docs/icons.md](docs/icons.md) — Font Awesome conventions, `{% uj_icon %}` vs prerendered icons in JS, size reference
|
|
203
|
+
- [docs/icons.md](docs/icons.md) — Font Awesome conventions, `{% uj_icon %}` vs prerendered icons in JS, size reference, country flag SVGs (`assets/icons/flags/modern-square/`)
|
|
204
204
|
- [docs/seo.md](docs/seo.md) — Alternatives collection (competitor comparison pages) + Schema/JSON-LD (`SoftwareApplication`, `FAQPage`)
|
|
205
205
|
|
|
206
206
|
### Frontend behavior
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="512" viewBox="0 0 152 152" width="512" xmlns="http://www.w3.org/2000/svg"><defs><clipPath id="clip"><path d="m124.81 149.4a459 459 0 0 1 -97.62 0 27.69 27.69 0 0 1 -24.59-24.59 459 459 0 0 1 0-97.62 27.69 27.69 0 0 1 24.59-24.59 459 459 0 0 1 97.62 0 27.69 27.69 0 0 1 24.59 24.59 459 459 0 0 1 0 97.62 27.69 27.69 0 0 1 -24.59 24.59z"/></clipPath></defs><g clip-path="url(#clip)"><rect width="152" height="76" fill="#f40055"/><rect y="76" width="152" height="76" fill="#f0f9ff"/></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="512" viewBox="0 0 152 152" width="512" xmlns="http://www.w3.org/2000/svg"><g id="Layer_2" data-name="Layer 2"><g id="india" data-name="india"><path id="path" d="m124.81 149.4a459 459 0 0 1 -97.62 0 27.69 27.69 0 0 1 -24.59-24.59 459 459 0 0 1 0-97.62 27.69 27.69 0 0 1 24.59-24.59 459 459 0 0 1 97.62 0 27.69 27.69 0 0 1 24.59 24.59 459 459 0 0 1 0 97.62 27.69 27.69 0 0 1 -24.59 24.59z" fill="#f0f9ff"/><path d="m151.38 52.26h-150.76q.63-12.54 2-25.08a27.68 27.68 0 0 1 24.57-24.58 459 459 0 0 1 97.62 0 27.68 27.68 0 0 1 24.59 24.58q1.33 12.53 1.98 25.08z" fill="#ff9933"/><path d="m151.38 99.73q-.63 12.54-2 25.08a27.68 27.68 0 0 1 -24.59 24.58 459 459 0 0 1 -97.62 0 27.68 27.68 0 0 1 -24.57-24.58q-1.34-12.54-2-25.08z" fill="#138808"/><circle cx="76" cy="76" r="13" fill="#000080"/><circle cx="76" cy="76" r="10.5" fill="#f0f9ff"/><circle cx="76" cy="76" r="3" fill="#000080"/></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="512" viewBox="0 0 152 152" width="512" xmlns="http://www.w3.org/2000/svg"><defs><clipPath id="clip"><path d="m124.81 149.4a459 459 0 0 1 -97.62 0 27.69 27.69 0 0 1 -24.59-24.59 459 459 0 0 1 0-97.62 27.69 27.69 0 0 1 24.59-24.59 459 459 0 0 1 97.62 0 27.69 27.69 0 0 1 24.59 24.59 459 459 0 0 1 0 97.62 27.69 27.69 0 0 1 -24.59 24.59z"/></clipPath></defs><g clip-path="url(#clip)"><rect width="152" height="76" fill="#406bd4"/><rect y="76" width="152" height="76" fill="#f40055"/><path d="m0 0v152l76-76z" fill="#f0f9ff"/><g fill="#ffcb24"><circle cx="25" cy="76" r="7"/><circle cx="10" cy="24" r="3.5"/><circle cx="10" cy="128" r="3.5"/><circle cx="52" cy="76" r="3.5"/></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="512" viewBox="0 0 152 152" width="512" xmlns="http://www.w3.org/2000/svg"><defs><clipPath id="clip"><path d="m124.81 149.4a459 459 0 0 1 -97.62 0 27.69 27.69 0 0 1 -24.59-24.59 459 459 0 0 1 0-97.62 27.69 27.69 0 0 1 24.59-24.59 459 459 0 0 1 97.62 0 27.69 27.69 0 0 1 24.59 24.59 459 459 0 0 1 0 97.62 27.69 27.69 0 0 1 -24.59 24.59z"/></clipPath></defs><g clip-path="url(#clip)"><rect width="152" height="152" fill="#01411c"/><rect width="38" height="152" fill="#f0f9ff"/><g transform="rotate(-270, 90, 76)"><circle cx="90" cy="76" r="24" fill="#f0f9ff"/><circle cx="82" cy="68" r="20" fill="#01411c"/></g><path d="m117.72 58.47a5 5 0 0 0 -4.5-5 5 5 0 0 0 -10 0 5 5 0 0 0 0 10 5 5 0 0 0 10 0 5 5 0 0 0 4.5-5z" fill="#f0f9ff"/></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="512" viewBox="0 0 152 152" width="512" xmlns="http://www.w3.org/2000/svg"><g id="Layer_2" data-name="Layer 2"><g id="russia" data-name="russia"><path id="path" d="m124.81 149.4a459 459 0 0 1 -97.62 0 27.69 27.69 0 0 1 -24.59-24.59 459 459 0 0 1 0-97.62 27.69 27.69 0 0 1 24.59-24.59 459 459 0 0 1 97.62 0 27.69 27.69 0 0 1 24.59 24.59 459 459 0 0 1 0 97.62 27.69 27.69 0 0 1 -24.59 24.59z" fill="#406bd4"/><path d="m151.38 52.26h-150.76q.63-12.54 2-25.08a27.68 27.68 0 0 1 24.57-24.58 459 459 0 0 1 97.62 0 27.68 27.68 0 0 1 24.59 24.58q1.33 12.53 1.98 25.08z" fill="#f0f9ff"/><path d="m151.38 99.73q-.63 12.54-2 25.08a27.68 27.68 0 0 1 -24.59 24.58 459 459 0 0 1 -97.62 0 27.68 27.68 0 0 1 -24.57-24.58q-1.34-12.54-2-25.08z" fill="#f40055"/></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="512" viewBox="0 0 152 152" width="512" xmlns="http://www.w3.org/2000/svg"><g id="Layer_2" data-name="Layer 2"><g id="vietnam" data-name="vietnam"><path id="path" d="m124.81 149.4a459 459 0 0 1 -97.62 0 27.69 27.69 0 0 1 -24.59-24.59 459 459 0 0 1 0-97.62 27.69 27.69 0 0 1 24.59-24.59 459 459 0 0 1 97.62 0 27.69 27.69 0 0 1 24.59 24.59 459 459 0 0 1 0 97.62 27.69 27.69 0 0 1 -24.59 24.59z" fill="#f40055"/><g transform="translate(20,0)"><path d="m84.77 66.21a5 5 0 0 0 -4.77-3.46h-12a3.67 3.67 0 0 1 -3.5-2.54l-3.78-11.47a5 5 0 0 0 -9.53 0l-3.72 11.47a3.67 3.67 0 0 1 -3.47 2.54h-12.09a5 5 0 0 0 -2.91 9.07l9.76 7.08a3.69 3.69 0 0 1 1.3 4.1l-3.73 11.49a5 5 0 0 0 7.71 5.6l9.76-7.09a3.66 3.66 0 0 1 4.32 0l9.76 7.09a5 5 0 0 0 7.71-5.6l-3.73-11.49a3.68 3.68 0 0 1 1.34-4.1l9.8-7.08a5 5 0 0 0 1.82-5.61z" fill="#ffcb24"/></g></g></g></svg>
|
package/dist/commands/setup.js
CHANGED
|
@@ -129,9 +129,9 @@ module.exports = async function (options) {
|
|
|
129
129
|
checkLocality();
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// Publish
|
|
132
|
+
// Publish .env secrets as repository secrets
|
|
133
133
|
if (options.publishGitHubToken) {
|
|
134
|
-
await
|
|
134
|
+
await publishSecrets();
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
// Deduplicate posts (remove duplicate posts with same slug but different dates)
|
|
@@ -389,7 +389,7 @@ function checkLocality() {
|
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
async function
|
|
392
|
+
async function publishSecrets() {
|
|
393
393
|
if (!process.env.GH_TOKEN) {
|
|
394
394
|
logger.warn('GH_TOKEN not found in environment variables. Skipping secret publication.');
|
|
395
395
|
return;
|
|
@@ -401,37 +401,67 @@ async function publishGitHubToken() {
|
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
if (Manager.isBuildMode()) {
|
|
404
|
-
logger.log('Skipping
|
|
404
|
+
logger.log('Skipping secret publication in build mode.');
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Read .env and collect all keys with non-empty values
|
|
409
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
410
|
+
if (!jetpack.exists(envPath)) {
|
|
411
|
+
logger.warn('.env file not found. Skipping secret publication.');
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const envContent = jetpack.read(envPath);
|
|
416
|
+
const secrets = {};
|
|
417
|
+
|
|
418
|
+
envContent.split('\n').forEach(line => {
|
|
419
|
+
const trimmed = line.trim();
|
|
420
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)=["']?(.+?)["']?$/);
|
|
424
|
+
if (match && match[2]) {
|
|
425
|
+
secrets[match[1]] = match[2];
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const secretNames = Object.keys(secrets);
|
|
430
|
+
if (!secretNames.length) {
|
|
431
|
+
logger.warn('No secrets with values found in .env. Skipping secret publication.');
|
|
405
432
|
return;
|
|
406
433
|
}
|
|
407
434
|
|
|
408
435
|
try {
|
|
409
436
|
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
|
|
410
|
-
|
|
411
437
|
const octokit = new Octokit({ auth: process.env.GH_TOKEN });
|
|
412
438
|
|
|
413
|
-
logger.log(`Publishing
|
|
439
|
+
logger.log(`Publishing ${secretNames.length} secret(s) for ${owner}/${repo}: ${secretNames.join(', ')}`);
|
|
414
440
|
|
|
415
441
|
await sodium.ready;
|
|
416
442
|
|
|
417
443
|
const { data: publicKeyData } = await octokit.actions.getRepoPublicKey({ owner, repo });
|
|
418
|
-
|
|
419
|
-
const secretBytes = Buffer.from(process.env.GH_TOKEN);
|
|
420
444
|
const keyBytes = Buffer.from(publicKeyData.key, 'base64');
|
|
421
|
-
const encryptedBytes = sodium.crypto_box_seal(secretBytes, keyBytes);
|
|
422
|
-
const encryptedValue = Buffer.from(encryptedBytes).toString('base64');
|
|
423
|
-
|
|
424
|
-
await octokit.actions.createOrUpdateRepoSecret({
|
|
425
|
-
owner,
|
|
426
|
-
repo,
|
|
427
|
-
secret_name: 'GH_TOKEN',
|
|
428
|
-
encrypted_value: encryptedValue,
|
|
429
|
-
key_id: publicKeyData.key_id,
|
|
430
|
-
});
|
|
431
445
|
|
|
432
|
-
|
|
446
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
447
|
+
const secretBytes = Buffer.from(value);
|
|
448
|
+
const encryptedBytes = sodium.crypto_box_seal(secretBytes, keyBytes);
|
|
449
|
+
const encryptedValue = Buffer.from(encryptedBytes).toString('base64');
|
|
450
|
+
|
|
451
|
+
await octokit.actions.createOrUpdateRepoSecret({
|
|
452
|
+
owner,
|
|
453
|
+
repo,
|
|
454
|
+
secret_name: name,
|
|
455
|
+
encrypted_value: encryptedValue,
|
|
456
|
+
key_id: publicKeyData.key_id,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
logger.log(` ✅ ${name}`);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
logger.log(`Successfully published ${secretNames.length} secret(s)`);
|
|
433
463
|
} catch (error) {
|
|
434
|
-
logger.error(`Failed to publish
|
|
464
|
+
logger.error(`Failed to publish secrets: ${error.message}`);
|
|
435
465
|
}
|
|
436
466
|
}
|
|
437
467
|
|
|
@@ -18,8 +18,7 @@ concurrency:
|
|
|
18
18
|
# contents: write
|
|
19
19
|
|
|
20
20
|
env:
|
|
21
|
-
|
|
22
|
-
BACKEND_MANAGER_KEY: ${{ secrets.BACKEND_MANAGER_KEY }}
|
|
21
|
+
{ github.secrets }
|
|
23
22
|
RUBY_VERSION: '{ versions.ruby }'
|
|
24
23
|
BUNDLER_VERSION: '{ versions.bundler }'
|
|
25
24
|
NODE_VERSION: '{ versions.node }'
|
|
@@ -30,6 +30,19 @@ const ujConfig = jetpack.exists(ujConfigPath) ? JSON5.parse(jetpack.read(ujConfi
|
|
|
30
30
|
// const cleanVersions = { versions: Manager.getCleanVersions()};
|
|
31
31
|
const cleanVersions = { versions: package.engines };
|
|
32
32
|
|
|
33
|
+
// Build GitHub Actions secrets env block from default .env
|
|
34
|
+
const defaultEnvPath = path.join(rootPathPackage, 'dist/defaults/_.env');
|
|
35
|
+
const githubSecrets = (() => {
|
|
36
|
+
const content = jetpack.exists(defaultEnvPath) ? jetpack.read(defaultEnvPath) : '';
|
|
37
|
+
const lines = content.split('\n')
|
|
38
|
+
.map(l => l.trim())
|
|
39
|
+
.filter(l => l && !l.startsWith('#') && l.includes('='))
|
|
40
|
+
.map(l => l.split('=')[0].trim())
|
|
41
|
+
.map(key => `${key}: \${{ secrets.${key} }}`);
|
|
42
|
+
|
|
43
|
+
return { github: { secrets: lines.join('\n ') } };
|
|
44
|
+
})();
|
|
45
|
+
|
|
33
46
|
// File MAP
|
|
34
47
|
const FILE_MAP = {
|
|
35
48
|
// Files to skip overwrite
|
|
@@ -116,7 +129,7 @@ const FILE_MAP = {
|
|
|
116
129
|
|
|
117
130
|
// Files to run templating on
|
|
118
131
|
'.github/workflows/build.yml': {
|
|
119
|
-
template: { ...cleanVersions, ...ujConfig },
|
|
132
|
+
template: { ...cleanVersions, ...ujConfig, ...githubSecrets },
|
|
120
133
|
},
|
|
121
134
|
'.nvmrc': {
|
|
122
135
|
template: cleanVersions,
|
|
@@ -158,7 +158,10 @@ function getSettings() {
|
|
|
158
158
|
const projectThemePath = path.resolve(rootPathProject, 'src/assets/themes', config.theme.id);
|
|
159
159
|
const ujmThemePath = path.resolve(rootPathPackage, 'dist/assets/themes', config.theme.id);
|
|
160
160
|
// Use project theme if it exists, otherwise fall back to UJM theme
|
|
161
|
-
|
|
161
|
+
const resolved = jetpack.exists(projectThemePath) ? projectThemePath : ujmThemePath;
|
|
162
|
+
// Ensure pages/ directory exists so dynamic imports don't fail
|
|
163
|
+
jetpack.dir(path.join(resolved, 'pages'));
|
|
164
|
+
return resolved;
|
|
162
165
|
})(),
|
|
163
166
|
},
|
|
164
167
|
// Add module resolution paths for local web-manager
|
package/docs/icons.md
CHANGED
|
@@ -117,6 +117,21 @@ $el.innerHTML = '<i class="fa-solid fa-check"></i> Text';
|
|
|
117
117
|
$el.innerHTML = `${getPrerenderedIcon('circle-check', 'fa-sm me-1')} Text`;
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
+
## Country Flag Icons
|
|
121
|
+
|
|
122
|
+
UJM ships rounded-square country flag SVGs at `assets/icons/flags/modern-square/`. The `{% uj_icon %}` tag resolves language codes to country flags via a `LANGUAGE_TO_COUNTRY` mapping in [jekyll-uj-powertools](https://github.com/itw-creative-works/jekyll-uj-powertools) (`lib/tags/icon.rb`). For example, `{% uj_icon "es" %}` resolves to `es.svg` (Spain), and `{% uj_icon "ja" %}` maps `ja` → `jp` → `jp.svg` (Japan).
|
|
123
|
+
|
|
124
|
+
Most flags are from a Flaticon rounded-square icon pack. The following 6 were hand-created to match the pack's style:
|
|
125
|
+
|
|
126
|
+
- `in.svg` (India) — saffron/white/green tricolor + Ashoka Chakra
|
|
127
|
+
- `ru.svg` (Russia) — white/blue/red tricolor
|
|
128
|
+
- `id.svg` (Indonesia) — red/white bicolor
|
|
129
|
+
- `vn.svg` (Vietnam) — red background + yellow star
|
|
130
|
+
- `pk.svg` (Pakistan) — green + white stripe, crescent & star
|
|
131
|
+
- `ph.svg` (Philippines) — blue/red + white triangle, sun & stars
|
|
132
|
+
|
|
133
|
+
When adding new flags, match the existing style: 152×152 viewBox, `clipPath` using the shared rounded-square path, flat/simplified design.
|
|
134
|
+
|
|
120
135
|
## Benefits
|
|
121
136
|
|
|
122
137
|
- Icons are rendered server-side with proper Font Awesome classes
|