nibula 1.6.1 → 1.6.2
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/.eleventy.js +1 -0
- package/CHANGELOG.md +11 -0
- package/bin/create.js +71 -36
- package/bin/delegate.js +2 -1
- package/docs/Styling with SCSS.md +9 -7
- package/package.json +1 -1
- package/src/frontend/layouts/base.njk +0 -1
- package/tools/cli/ui.js +6 -6
package/.eleventy.js
CHANGED
|
@@ -33,6 +33,7 @@ module.exports = function (eleventyConfig) {
|
|
|
33
33
|
eleventyConfig.addPassthroughCopy("src/frontend/robots.txt");
|
|
34
34
|
|
|
35
35
|
eleventyConfig.addPassthroughCopy({
|
|
36
|
+
// Bootstrap
|
|
36
37
|
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js": "js/bootstrap.bundle.min.js",
|
|
37
38
|
"node_modules/bootstrap-icons/font/fonts": "css/fonts",
|
|
38
39
|
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to Nibula are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.6.2] - 2026-08-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `nib --version` (also `-v`, `v`, `version`) prints the version number on its own line. Inside a project it reports the project's own copy, which is the one actually running the command.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
[...le quattro voci di prima, invariate...]
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- `docs/Styling with SCSS.md` now matches the template: the Nunjucks snippets include the `url` filter and the config file is named `.eleventy.js`.
|
|
18
|
+
|
|
8
19
|
## [1.6.1] - 2026-08-06
|
|
9
20
|
|
|
10
21
|
### Fixed
|
package/bin/create.js
CHANGED
|
@@ -33,6 +33,11 @@ const BACKEND = Object.freeze({
|
|
|
33
33
|
PHP: 'php',
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
+
const COMMENT_STYLE = Object.freeze({
|
|
37
|
+
SLASH: { open: '// ', close: '' },
|
|
38
|
+
NJK: { open: '{# ', close: ' #}' },
|
|
39
|
+
});
|
|
40
|
+
|
|
36
41
|
// ── CHOICES ──────────────────────────────────────────────────────────────────
|
|
37
42
|
|
|
38
43
|
const LANGUAGE_CHOICES = [
|
|
@@ -88,14 +93,16 @@ const BACKEND_SKIP_DIRS = new Set(['node_modules', 'cache', '.git']);
|
|
|
88
93
|
|
|
89
94
|
const ALL_FRAMEWORKS = Object.values(FRAMEWORK).filter(f => f !== FRAMEWORK.NONE);
|
|
90
95
|
|
|
96
|
+
const SCSS_FRAMEWORK_PREFIX = 'modules/frameworks/';
|
|
97
|
+
|
|
98
|
+
// Markers are substrings matched against whole lines, never full lines, so the
|
|
99
|
+
// surrounding syntax (Nunjucks url filter, passthrough copy mapping) can change
|
|
100
|
+
// without breaking the scaffolder.
|
|
91
101
|
const FRAMEWORKS = {
|
|
92
102
|
[FRAMEWORK.BOOTSTRAP]: {
|
|
93
103
|
scss: 'bootstrap',
|
|
94
|
-
njk: ['
|
|
95
|
-
eleventy: [
|
|
96
|
-
'"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js": "js/bootstrap.bundle.min.js",',
|
|
97
|
-
'"node_modules/bootstrap-icons/font/fonts": "css/fonts",',
|
|
98
|
-
],
|
|
104
|
+
njk: ['/js/bootstrap.bundle.min.js'],
|
|
105
|
+
eleventy: ['bootstrap/dist/js/bootstrap.bundle.min.js', 'bootstrap-icons/font/fonts'],
|
|
99
106
|
},
|
|
100
107
|
[FRAMEWORK.BULMA]: {
|
|
101
108
|
scss: 'bulma',
|
|
@@ -104,19 +111,13 @@ const FRAMEWORKS = {
|
|
|
104
111
|
},
|
|
105
112
|
[FRAMEWORK.FOUNDATION]: {
|
|
106
113
|
scss: 'foundation',
|
|
107
|
-
njk: ['
|
|
108
|
-
eleventy: ['
|
|
114
|
+
njk: ['/js/foundation.min.js'],
|
|
115
|
+
eleventy: ['foundation-sites/dist/js/foundation.min.js'],
|
|
109
116
|
},
|
|
110
117
|
[FRAMEWORK.UIKIT]: {
|
|
111
118
|
scss: 'uikit',
|
|
112
|
-
njk: [
|
|
113
|
-
|
|
114
|
-
'<script src="/js/uikit-icons.min.js" defer></script>',
|
|
115
|
-
],
|
|
116
|
-
eleventy: [
|
|
117
|
-
'"node_modules/uikit/dist/js/uikit.min.js": "js/uikit.min.js",',
|
|
118
|
-
'"node_modules/uikit/dist/js/uikit-icons.min.js": "js/uikit-icons.min.js",',
|
|
119
|
-
],
|
|
119
|
+
njk: ['/js/uikit.min.js', '/js/uikit-icons.min.js'],
|
|
120
|
+
eleventy: ['uikit/dist/js/uikit.min.js', 'uikit/dist/js/uikit-icons.min.js'],
|
|
120
121
|
},
|
|
121
122
|
[FRAMEWORK.NONE]: {
|
|
122
123
|
scss: null,
|
|
@@ -189,10 +190,6 @@ function logAdd(name) {
|
|
|
189
190
|
log(`${color.green}+${color.reset} ${name}`);
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
function escapeRegex(str) {
|
|
193
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
193
|
function copyRecursive(src, dest, exclude = []) {
|
|
197
194
|
const stat = fs.statSync(src);
|
|
198
195
|
if (stat.isDirectory()) {
|
|
@@ -250,22 +247,60 @@ function copyBackend(src, dest, backend) {
|
|
|
250
247
|
}
|
|
251
248
|
}
|
|
252
249
|
|
|
253
|
-
function
|
|
254
|
-
|
|
255
|
-
|
|
250
|
+
function splitLine(line) {
|
|
251
|
+
const body = line.trim();
|
|
252
|
+
if (!body) return { indent: line, body: '', trailing: '' };
|
|
253
|
+
|
|
254
|
+
const start = line.indexOf(body);
|
|
255
|
+
return {
|
|
256
|
+
indent: line.slice(0, start),
|
|
257
|
+
body,
|
|
258
|
+
trailing: line.slice(start + body.length),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function uncommentLine(line, style) {
|
|
263
|
+
const { indent, body, trailing } = splitLine(line);
|
|
264
|
+
if (!body.startsWith(style.open)) return line;
|
|
265
|
+
|
|
266
|
+
let inner = body.slice(style.open.length);
|
|
267
|
+
if (style.close) {
|
|
268
|
+
if (!inner.endsWith(style.close)) return line;
|
|
269
|
+
inner = inner.slice(0, -style.close.length);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return indent + inner + trailing;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function commentLine(line, style) {
|
|
276
|
+
const bare = uncommentLine(line, style);
|
|
277
|
+
const { indent, body, trailing } = splitLine(bare);
|
|
278
|
+
if (!body) return line;
|
|
279
|
+
|
|
280
|
+
return indent + style.open + body + style.close + trailing;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function mapMarkedLines(content, marker, style, transform) {
|
|
284
|
+
return content
|
|
285
|
+
.split('\n')
|
|
286
|
+
.map(line => (line.includes(marker) ? transform(line, style) : line))
|
|
287
|
+
.join('\n');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function slashComment(content, marker) {
|
|
291
|
+
return mapMarkedLines(content, marker, COMMENT_STYLE.SLASH, commentLine);
|
|
256
292
|
}
|
|
257
293
|
|
|
258
|
-
function slashUncomment(content,
|
|
259
|
-
return content
|
|
294
|
+
function slashUncomment(content, marker) {
|
|
295
|
+
return mapMarkedLines(content, marker, COMMENT_STYLE.SLASH, uncommentLine);
|
|
260
296
|
}
|
|
261
297
|
|
|
262
|
-
function njkComment(content,
|
|
263
|
-
content
|
|
264
|
-
return content.split(line).join(`{# ${line} #}`);
|
|
298
|
+
function njkComment(content, marker) {
|
|
299
|
+
return mapMarkedLines(content, marker, COMMENT_STYLE.NJK, commentLine);
|
|
265
300
|
}
|
|
266
301
|
|
|
267
|
-
function njkUncomment(content,
|
|
268
|
-
return content
|
|
302
|
+
function njkUncomment(content, marker) {
|
|
303
|
+
return mapMarkedLines(content, marker, COMMENT_STYLE.NJK, uncommentLine);
|
|
269
304
|
}
|
|
270
305
|
|
|
271
306
|
function installDependencies(backend) {
|
|
@@ -323,14 +358,14 @@ function installDependencies(backend) {
|
|
|
323
358
|
function applyFramework(framework) {
|
|
324
359
|
const config = FRAMEWORKS[framework];
|
|
325
360
|
|
|
326
|
-
const globalScssPath = path.join(targetDir, 'src/frontend/scss/
|
|
361
|
+
const globalScssPath = path.join(targetDir, 'src/frontend/scss/_global.scss');
|
|
327
362
|
if (fs.existsSync(globalScssPath)) {
|
|
328
363
|
let content = fs.readFileSync(globalScssPath, 'utf8');
|
|
329
364
|
ALL_FRAMEWORKS.forEach(fw => {
|
|
330
|
-
content = slashComment(content,
|
|
365
|
+
content = slashComment(content, `${SCSS_FRAMEWORK_PREFIX}${fw}`);
|
|
331
366
|
});
|
|
332
367
|
if (config.scss) {
|
|
333
|
-
content = slashUncomment(content,
|
|
368
|
+
content = slashUncomment(content, `${SCSS_FRAMEWORK_PREFIX}${config.scss}`);
|
|
334
369
|
}
|
|
335
370
|
fs.writeFileSync(globalScssPath, content);
|
|
336
371
|
}
|
|
@@ -339,9 +374,9 @@ function applyFramework(framework) {
|
|
|
339
374
|
if (fs.existsSync(baseNjkPath)) {
|
|
340
375
|
let content = fs.readFileSync(baseNjkPath, 'utf8');
|
|
341
376
|
ALL_FRAMEWORKS.forEach(fw => {
|
|
342
|
-
FRAMEWORKS[fw].njk.forEach(
|
|
377
|
+
FRAMEWORKS[fw].njk.forEach(marker => { content = njkComment(content, marker); });
|
|
343
378
|
});
|
|
344
|
-
config.njk.forEach(
|
|
379
|
+
config.njk.forEach(marker => { content = njkUncomment(content, marker); });
|
|
345
380
|
fs.writeFileSync(baseNjkPath, content);
|
|
346
381
|
}
|
|
347
382
|
|
|
@@ -349,9 +384,9 @@ function applyFramework(framework) {
|
|
|
349
384
|
if (fs.existsSync(eleventyPath)) {
|
|
350
385
|
let content = fs.readFileSync(eleventyPath, 'utf8');
|
|
351
386
|
ALL_FRAMEWORKS.forEach(fw => {
|
|
352
|
-
FRAMEWORKS[fw].eleventy.forEach(
|
|
387
|
+
FRAMEWORKS[fw].eleventy.forEach(marker => { content = slashComment(content, marker); });
|
|
353
388
|
});
|
|
354
|
-
config.eleventy.forEach(
|
|
389
|
+
config.eleventy.forEach(marker => { content = slashUncomment(content, marker); });
|
|
355
390
|
fs.writeFileSync(eleventyPath, content);
|
|
356
391
|
}
|
|
357
392
|
}
|
package/bin/delegate.js
CHANGED
|
@@ -10,6 +10,7 @@ const ENTRY_FILE = path.join('bin', 'nibula.js');
|
|
|
10
10
|
const PACKAGE_FILE = 'package.json';
|
|
11
11
|
const LOCAL_FLAG = 'NIBULA_LOCAL';
|
|
12
12
|
const LOCAL_FLAG_VALUE = '1';
|
|
13
|
+
const GLOBAL_VERSION_FLAG = 'NIBULA_GLOBAL_VERSION';
|
|
13
14
|
|
|
14
15
|
const globalVersion = require(`../${PACKAGE_FILE}`).version;
|
|
15
16
|
|
|
@@ -49,7 +50,7 @@ function delegateToLocal(projectRoot) {
|
|
|
49
50
|
const result = spawnSync(process.execPath, [localEntry, ...process.argv.slice(2)], {
|
|
50
51
|
stdio: 'inherit',
|
|
51
52
|
cwd: process.cwd(),
|
|
52
|
-
env: { ...process.env, [LOCAL_FLAG]: LOCAL_FLAG_VALUE },
|
|
53
|
+
env: { ...process.env, [LOCAL_FLAG]: LOCAL_FLAG_VALUE, [GLOBAL_VERSION_FLAG]: globalVersion },
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
process.exit(result.status ?? 0);
|
|
@@ -31,7 +31,7 @@ body {
|
|
|
31
31
|
|
|
32
32
|
Instead of using `:root` in your custom modules or pages, the best thing to do is to centralize all your variables in a single file (that will be tree-shaken automatically by Sass)
|
|
33
33
|
|
|
34
|
-
### _root.scss <small>(`src/frontend/scss
|
|
34
|
+
### _root.scss <small>(`src/frontend/scss/`)</small>
|
|
35
35
|
```scss
|
|
36
36
|
$header-height: 10vh;
|
|
37
37
|
|
|
@@ -51,6 +51,8 @@ You can create subfolders if you want to refactor the structure, but be sure to
|
|
|
51
51
|
```scss
|
|
52
52
|
@use '../../root' as root;
|
|
53
53
|
|
|
54
|
+
@import '../../global';
|
|
55
|
+
|
|
54
56
|
body {
|
|
55
57
|
background-color: root.$primary;
|
|
56
58
|
}
|
|
@@ -97,19 +99,19 @@ To enable/disable them you have to modify 3 files around the project by just com
|
|
|
97
99
|
|
|
98
100
|
```html
|
|
99
101
|
{# Bootstrap JS #}
|
|
100
|
-
<script src="/js/bootstrap.bundle.min.js" defer></script>
|
|
102
|
+
<script src="{{ '/js/bootstrap.bundle.min.js' | url }}" defer></script>
|
|
101
103
|
|
|
102
104
|
{# Foundation JS #}
|
|
103
|
-
{# <script src="/js/foundation.min.js" defer></script> #}
|
|
105
|
+
{# <script src="{{ '/js/foundation.min.js' | url }}" defer></script> #}
|
|
104
106
|
|
|
105
107
|
{# UIkit JS #}
|
|
106
|
-
{# <script src="/js/uikit.min.js" defer></script> #}
|
|
107
|
-
{# <script src="/js/uikit-icons.min.js" defer></script> #}
|
|
108
|
+
{# <script src="{{ '/js/uikit.min.js' | url }}" defer></script> #}
|
|
109
|
+
{# <script src="{{ '/js/uikit-icons.min.js' | url }}" defer></script> #}
|
|
108
110
|
|
|
109
111
|
{# Bulma — no JS needed #}
|
|
110
112
|
```
|
|
111
113
|
|
|
112
|
-
### 3. eleventy.
|
|
114
|
+
### 3. eleventy.js
|
|
113
115
|
|
|
114
116
|
```javascript
|
|
115
117
|
eleventyConfig.addPassthroughCopy({
|
|
@@ -128,7 +130,7 @@ eleventyConfig.addPassthroughCopy({
|
|
|
128
130
|
});
|
|
129
131
|
```
|
|
130
132
|
|
|
131
|
-
> ⚠️ Changes to `eleventy.
|
|
133
|
+
> ⚠️ Changes to `eleventy.js` are not picked up while the dev server is running — restart it.
|
|
132
134
|
|
|
133
135
|
### Reducing bundle size
|
|
134
136
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nibula",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "A beginner-friendly static site generator built on Eleventy that stays close to vanilla HTML, CSS and JS — with a page-management CLI, an optional PHP backend, and SEO files generated for you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"11ty",
|
package/tools/cli/ui.js
CHANGED
|
@@ -15,12 +15,14 @@ const BOX_VERTICAL = '\u2502';
|
|
|
15
15
|
const NEW_LINE = '\n';
|
|
16
16
|
const SPACE = ' ';
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const LOCAL_FLAG_VALUE = '1';
|
|
18
|
+
const GLOBAL_VERSION_FLAG = 'NIBULA_GLOBAL_VERSION';
|
|
20
19
|
const TITLE_PADDING = 2;
|
|
21
20
|
|
|
22
|
-
const
|
|
23
|
-
|
|
21
|
+
const LOCAL_VERSION = require('../../package.json').version;
|
|
22
|
+
const GLOBAL_VERSION = process.env[GLOBAL_VERSION_FLAG];
|
|
23
|
+
|
|
24
|
+
const TITLE_SUFFIX = GLOBAL_VERSION && GLOBAL_VERSION !== LOCAL_VERSION
|
|
25
|
+
? ` (local v${LOCAL_VERSION})`
|
|
24
26
|
: '';
|
|
25
27
|
|
|
26
28
|
const PLAIN_TITLE = `${BOX_TITLE}${TITLE_SUFFIX}`;
|
|
@@ -55,8 +57,6 @@ function centeredTitle() {
|
|
|
55
57
|
const left = SPACE.repeat(Math.ceil(padding / 2));
|
|
56
58
|
const right = SPACE.repeat(Math.floor(padding / 2));
|
|
57
59
|
|
|
58
|
-
if (!TITLE_SUFFIX) return `${left}${BOX_TITLE}${right}`;
|
|
59
|
-
|
|
60
60
|
const suffix = `${color.dim}${TITLE_SUFFIX}${color.reset}${color[COLORS.box]}${color.bold}`;
|
|
61
61
|
return `${left}${BOX_TITLE}${suffix}${right}`;
|
|
62
62
|
}
|