create-berna-stencil 2.0.4 → 2.0.5
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.
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// Call anywhere
|
|
6
6
|
import { showNotification } from '../modules/notification.js';
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// Example of pre-existing modules
|
|
9
9
|
// import { initTextAreaAutoExpand } from '../modules/forms/textAreaAutoExpand.js';
|
|
10
10
|
// import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
|
|
11
11
|
|
|
@@ -14,6 +14,8 @@ import { showNotification } from '../modules/notification.js';
|
|
|
14
14
|
//==========================
|
|
15
15
|
|
|
16
16
|
document.addEventListener("DOMContentLoaded", () => {
|
|
17
|
+
// initTextAreaAutoExpand();
|
|
18
|
+
// initNormalizePhoneNumber();
|
|
17
19
|
});
|
|
18
20
|
|
|
19
21
|
showNotification("Example notification", "success", 3000);
|
package/bin/create.js
CHANGED
|
@@ -15,7 +15,7 @@ const COPY_TARGETS = [
|
|
|
15
15
|
|
|
16
16
|
const PROJECT_PACKAGE = {
|
|
17
17
|
name: path.basename(targetDir),
|
|
18
|
-
version: '2.0.
|
|
18
|
+
version: '2.0.5',
|
|
19
19
|
private: true,
|
|
20
20
|
scripts: {
|
|
21
21
|
"build:css": "sass src/frontend/scss:out/css --no-source-map --style=compressed --quiet --load-path=node_modules",
|
package/docs/Backend.md
CHANGED
|
@@ -104,9 +104,9 @@ To assign a dedicated key, add it to `config.php`:
|
|
|
104
104
|
## The Response helper
|
|
105
105
|
|
|
106
106
|
```php
|
|
107
|
-
Response::success($data, $code);
|
|
107
|
+
Response::success($data, $code); // default 200
|
|
108
108
|
Response::error($message, $code, $details); // default 400
|
|
109
|
-
Response::noContent();
|
|
109
|
+
Response::noContent(); // 204
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
## Handling multiple methods
|
package/docs/Javascript.md
CHANGED
|
@@ -10,11 +10,12 @@ Import only what the page needs.
|
|
|
10
10
|
|
|
11
11
|
### examplePage.js <small>(`src/frontend/js/pages/`)</small>
|
|
12
12
|
```js
|
|
13
|
-
import { initLangSwitcher } from '../modules/langSwitcher.js';
|
|
14
13
|
import { showNotification } from '../modules/notification.js';
|
|
15
14
|
|
|
15
|
+
import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
|
|
16
|
+
|
|
16
17
|
document.addEventListener("DOMContentLoaded", () => {
|
|
17
|
-
|
|
18
|
+
initNormalizePhoneNumber();
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
showNotification("Page loaded", "success", 3000);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-berna-stencil",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Eleventy boilerplate with per-page SCSS/JS pipeline, esbuild bundling, multi-framework CSS support and a built-in page management CLI",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Michele Garofalo",
|
package/src/frontend/404.njk
CHANGED
|
@@ -7,7 +7,7 @@ layout: base.njk
|
|
|
7
7
|
<!-- !IMPORTANT -->
|
|
8
8
|
<!-- This is the only page that you need to modify statically -->
|
|
9
9
|
|
|
10
|
-
<div class="fade-in
|
|
10
|
+
<div class="fade-in center">
|
|
11
11
|
<h1>Oops! Page not found</h1>
|
|
12
12
|
<a href="/">Return to homepage</a>
|
|
13
13
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<div class="container my-3">
|
|
1
|
+
<div class="layout-container layout-my-3">
|
|
2
2
|
<h1>Welcome to <span class="berna-stencil">Berna-Stencil</span></h1>
|
|
3
3
|
<div class="slogan">The boilerplate you need, simplified</div>
|
|
4
4
|
|
|
@@ -42,16 +42,29 @@
|
|
|
42
42
|
<div id="content-welcome" class="tab-content active">
|
|
43
43
|
<div class="grid" style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
|
44
44
|
<a href="https://bernastencil.com" class="card" target="_blank" rel="noopener noreferrer" style="flex: 1; min-width: 250px;">
|
|
45
|
-
<
|
|
45
|
+
<svg class="card-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
46
|
+
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
|
|
47
|
+
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
|
|
48
|
+
</svg>
|
|
46
49
|
<h3>Documentation</h3>
|
|
47
50
|
<p>Everything you need to get started, from setup to advanced topics and customizations</p>
|
|
48
|
-
<span class="card-link">Go to documentation
|
|
51
|
+
<span class="card-link">Go to documentation
|
|
52
|
+
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" style="margin-left:4px;">
|
|
53
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
|
54
|
+
</svg>
|
|
55
|
+
</span>
|
|
49
56
|
</a>
|
|
50
57
|
<a href="https://github.com/rhaastrake/berna-stencil" class="card" target="_blank" rel="noopener noreferrer" style="flex: 1; min-width: 250px;">
|
|
51
|
-
<
|
|
58
|
+
<svg class="card-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
59
|
+
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
|
60
|
+
</svg>
|
|
52
61
|
<h3>Github repository</h3>
|
|
53
62
|
<p>Community-driven. Contributions, issues and PRs are welcome.</p>
|
|
54
|
-
<span class="card-link">Open the repository
|
|
63
|
+
<span class="card-link">Open the repository
|
|
64
|
+
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" style="margin-left:4px;">
|
|
65
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
|
|
66
|
+
</svg>
|
|
67
|
+
</span>
|
|
55
68
|
</a>
|
|
56
69
|
</div>
|
|
57
70
|
</div>
|
|
@@ -215,23 +228,27 @@ body {
|
|
|
215
228
|
<div id="content-javascript" class="tab-content">
|
|
216
229
|
<div class="markdown-body">
|
|
217
230
|
<h2>JavaScript</h2>
|
|
231
|
+
|
|
218
232
|
<h3>Page JS</h3>
|
|
219
233
|
<p>Each page has its own JS entry point in <code>src/frontend/js/pages/</code></p>
|
|
220
234
|
<p>It is bundled and minified by esbuild and loaded automatically by <code>base.njk</code></p>
|
|
221
235
|
<p>Import only what the page needs.</p>
|
|
236
|
+
|
|
222
237
|
<h4>examplePage.js <small>(<code>src/frontend/js/pages/</code>)</small></h4>
|
|
223
|
-
<pre><code>
|
|
224
|
-
import { initLangSwitcher } from '../modules/langSwitcher.js';
|
|
225
|
-
import { showNotification } from '../modules/notification.js';
|
|
238
|
+
<pre><code class="language-js">import { showNotification } from '../modules/notification.js';
|
|
226
239
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
240
|
+
import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
|
|
241
|
+
|
|
242
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
243
|
+
initNormalizePhoneNumber();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
showNotification("Page loaded", "success", 3000);</code></pre>
|
|
230
247
|
|
|
231
|
-
|
|
232
|
-
<h3>Modules</h3>
|
|
248
|
+
<h2>Modules</h2>
|
|
233
249
|
<p>Modules live in <code>src/frontend/js/modules/</code>. Some must be called inside <code>DOMContentLoaded</code> as they interact with the DOM; others create elements dynamically and can be called anywhere.</p>
|
|
234
|
-
|
|
250
|
+
|
|
251
|
+
<h3>Call inside <code>DOMContentLoaded</code></h3>
|
|
235
252
|
<table>
|
|
236
253
|
<thead>
|
|
237
254
|
<tr><th>Module</th><th>Function</th></tr>
|
|
@@ -243,7 +260,8 @@ showNotification("Page loaded", "success", 3000);</code></pre>
|
|
|
243
260
|
<tr><td><code>modules/forms/normalizePhoneNumber.js</code></td><td><code>initNormalizePhoneNumber()</code></td></tr>
|
|
244
261
|
</tbody>
|
|
245
262
|
</table>
|
|
246
|
-
|
|
263
|
+
|
|
264
|
+
<h3>Call anywhere</h3>
|
|
247
265
|
<table>
|
|
248
266
|
<thead>
|
|
249
267
|
<tr><th>Module</th><th>Function</th></tr>
|
|
@@ -252,7 +270,8 @@ showNotification("Page loaded", "success", 3000);</code></pre>
|
|
|
252
270
|
<tr><td><code>modules/notification.js</code></td><td><code>showNotification(text, type, duration)</code></td></tr>
|
|
253
271
|
</tbody>
|
|
254
272
|
</table>
|
|
255
|
-
|
|
273
|
+
|
|
274
|
+
<h3><code>showNotification</code> parameters</h3>
|
|
256
275
|
<table>
|
|
257
276
|
<thead>
|
|
258
277
|
<tr><th>Parameter</th><th>Type</th><th>Default</th><th>Values</th></tr>
|
|
@@ -263,18 +282,24 @@ showNotification("Page loaded", "success", 3000);</code></pre>
|
|
|
263
282
|
<tr><td><code>duration</code></td><td>number</td><td><code>5000</code></td><td>ms, or <code>-1</code> for persistent with spinner</td></tr>
|
|
264
283
|
</tbody>
|
|
265
284
|
</table>
|
|
266
|
-
|
|
285
|
+
|
|
286
|
+
<h2>Adding a module</h2>
|
|
267
287
|
<p>Create a new <code>.js</code> file in <code>src/frontend/js/modules/</code>. You can organize them into subfolders freely.</p>
|
|
268
288
|
<p>Use ESM syntax — esbuild handles the bundling:</p>
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
289
|
+
|
|
290
|
+
<pre><code class="language-js">// _yourModule.js
|
|
291
|
+
export function yourFunction() {
|
|
292
|
+
// ...
|
|
293
|
+
}</code></pre>
|
|
294
|
+
|
|
273
295
|
<p>Then import it in the pages that need it:</p>
|
|
274
|
-
|
|
296
|
+
|
|
297
|
+
<pre><code class="language-js">import { yourFunction } from '../modules/yourModule.js';</code></pre>
|
|
298
|
+
|
|
275
299
|
<blockquote>⚠️ Files inside <code>_tools/</code> run directly in Node.js without a bundler — use CommonJS (<code>require</code> / <code>module.exports</code>) there, not ESM.</blockquote>
|
|
276
300
|
</div>
|
|
277
301
|
</div>
|
|
302
|
+
</div>
|
|
278
303
|
|
|
279
304
|
<div id="content-creating-pages" class="tab-content">
|
|
280
305
|
<div class="markdown-body">
|
|
@@ -375,39 +400,45 @@ export function yourFunction() {
|
|
|
375
400
|
<div class="markdown-body">
|
|
376
401
|
<h2>Head & SEO</h2>
|
|
377
402
|
<p>This json holds global settings used across all pages in <code>base.njk</code> and other components:</p>
|
|
403
|
+
|
|
378
404
|
<h3>site.json <small>(<code>src/frontend/data/</code>)</small></h3>
|
|
379
|
-
<pre><code>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
405
|
+
<pre><code>"site_name": "Site name",
|
|
406
|
+
"title": "Site title",
|
|
407
|
+
"description": "Site description",
|
|
408
|
+
"keywords": "keyword1, keyword2, keyword3",
|
|
409
|
+
"domain": "yoursite.com",
|
|
410
|
+
"url": "https://yoursite.com",
|
|
411
|
+
"lang": "en",
|
|
412
|
+
"author": "Name and surname",
|
|
413
|
+
"data_bs_theme": "dark",
|
|
414
|
+
"favicon": "/assets/brand/favicon.svg",
|
|
415
|
+
"logo": "/assets/brand/logo.svg",
|
|
416
|
+
...</code></pre>
|
|
417
|
+
|
|
392
418
|
<h2>Per-page SEO and CDN</h2>
|
|
393
|
-
<p>Each page entry is keyed by its camelCase <code>title</code> from the front matter
|
|
419
|
+
<p>Each page entry is keyed by its camelCase <code>title</code> from the front matter:</p>
|
|
394
420
|
<p>If you don't want to use a particular CDN inserting it in <code>base.njk</code> for all pages, you can add extra specific CDN (CSS, JS) by inserting the link in each page of <code>site.json</code> separating them with a <code>,</code> and setting them in <code>""</code>.</p>
|
|
421
|
+
|
|
395
422
|
<h3>site.json <small>(<code>src/frontend/data/</code>)</small></h3>
|
|
396
423
|
<pre><code>"pages": {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
424
|
+
...
|
|
425
|
+
"examplePage": {
|
|
426
|
+
"seo": {
|
|
427
|
+
"title": "Example Page",
|
|
428
|
+
"description": "description"
|
|
429
|
+
},
|
|
430
|
+
"cdn": {
|
|
431
|
+
// You can leave the [] empty
|
|
432
|
+
"css": ["https://example1.com/lib.min.css", "https://example2.com/lib.min.css"],
|
|
433
|
+
"js": ["https://example1.com/lib.min.js", "https://example2.com/lib.min.js"]
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
...
|
|
437
|
+
}</code></pre>
|
|
438
|
+
|
|
409
439
|
<h2>AI & SEO bots</h2>
|
|
410
440
|
<p><code>llms.txt</code> and <code>robots.txt</code> are generated automatically from <code>site.json</code> via their respective <code>.njk</code> files — no manual editing needed.</p>
|
|
441
|
+
|
|
411
442
|
<table>
|
|
412
443
|
<thead>
|
|
413
444
|
<tr><th>File</th><th>Purpose</th><th>Reachable at</th></tr>
|
|
@@ -417,7 +448,29 @@ export function yourFunction() {
|
|
|
417
448
|
<tr><td><code>robots.njk</code></td><td>Controls search engine crawling</td><td><code>yoursite.com/robots.txt</code></td></tr>
|
|
418
449
|
</tbody>
|
|
419
450
|
</table>
|
|
451
|
+
|
|
420
452
|
<p>To customize them, edit <code>src/llms.njk</code> or <code>src/robots.njk</code> directly.</p>
|
|
453
|
+
|
|
454
|
+
<h3>Customizing llms.txt</h3>
|
|
455
|
+
<p><code>src/llms.njk</code> ships with a base template — <strong>replace the placeholders with your own content</strong>:</p>
|
|
456
|
+
|
|
457
|
+
<pre><code># Site name
|
|
458
|
+
|
|
459
|
+
> Site description
|
|
460
|
+
|
|
461
|
+
Built by Name and surname — https://yoursite.com
|
|
462
|
+
|
|
463
|
+
## Pages
|
|
464
|
+
|
|
465
|
+
- https://yoursite.com: Homepage
|
|
466
|
+
|
|
467
|
+
## Notes
|
|
468
|
+
|
|
469
|
+
- Language: en
|
|
470
|
+
- All content may be used for AI indexing unless otherwise stated</code></pre>
|
|
471
|
+
|
|
472
|
+
<blockquote>The more accurate and detailed your <code>llms.txt</code>, the better AI models will understand and reference your site.</blockquote>
|
|
473
|
+
|
|
421
474
|
<h2>Configuration field description</h2>
|
|
422
475
|
<table>
|
|
423
476
|
<thead>
|
|
@@ -516,7 +569,7 @@ Response::success(['visits' => 1024]);</code></pre>
|
|
|
516
569
|
'admin/stats' => 'secret-stats-key',
|
|
517
570
|
],</code></pre>
|
|
518
571
|
<h3>The Response helper</h3>
|
|
519
|
-
<pre><code>Response::success($data, $code);
|
|
572
|
+
<pre><code>Response::success($data, $code); // default 200
|
|
520
573
|
Response::error($message, $code, $details); // default 400
|
|
521
574
|
Response::noContent(); // 204</code></pre>
|
|
522
575
|
<h3>Handling multiple methods</h3>
|
|
@@ -611,6 +664,20 @@ const res = await fetch('/api/posts', {
|
|
|
611
664
|
</div>
|
|
612
665
|
|
|
613
666
|
<style>
|
|
667
|
+
/* Custom Replacement Classes for Bootstrap */
|
|
668
|
+
.layout-container {
|
|
669
|
+
width: 100%;
|
|
670
|
+
max-width: 1140px;
|
|
671
|
+
margin-right: auto;
|
|
672
|
+
margin-left: auto;
|
|
673
|
+
padding-right: 15px;
|
|
674
|
+
padding-left: 15px;
|
|
675
|
+
}
|
|
676
|
+
.layout-my-3 {
|
|
677
|
+
margin-top: 1rem;
|
|
678
|
+
margin-bottom: 1rem;
|
|
679
|
+
}
|
|
680
|
+
|
|
614
681
|
h1 {
|
|
615
682
|
text-align: center;
|
|
616
683
|
font-weight: 400;
|
|
@@ -659,7 +726,8 @@ const res = await fetch('/api/posts', {
|
|
|
659
726
|
transform: translateY(-2px);
|
|
660
727
|
}
|
|
661
728
|
.card-icon {
|
|
662
|
-
|
|
729
|
+
width: 2rem;
|
|
730
|
+
height: 2rem;
|
|
663
731
|
color: #42b883;
|
|
664
732
|
}
|
|
665
733
|
.card h3 {
|
|
@@ -824,6 +892,7 @@ const res = await fetch('/api/posts', {
|
|
|
824
892
|
}
|
|
825
893
|
});
|
|
826
894
|
});
|
|
895
|
+
|
|
827
896
|
document.querySelector('.nav-to-assistant').addEventListener('click', (e) => {
|
|
828
897
|
e.preventDefault();
|
|
829
898
|
|
|
@@ -834,7 +903,8 @@ const res = await fetch('/api/posts', {
|
|
|
834
903
|
assistantRadio.dispatchEvent(new Event('change'));
|
|
835
904
|
}
|
|
836
905
|
});
|
|
837
|
-
|
|
906
|
+
|
|
907
|
+
document.querySelector('.nav-to-head-seo').addEventListener('click', (e) => {
|
|
838
908
|
e.preventDefault();
|
|
839
909
|
|
|
840
910
|
const headAndSeoRadio = document.querySelector('input[name="guide-filter"][value="head-seo"]');
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
|
|
19
19
|
// Add any custom rule specific to this page below
|
|
20
20
|
// These rules override the framework and module styles
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
.center {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
align-items: center;
|
|
26
|
+
min-height: 60vh;
|
|
27
|
+
text-align: center;
|
|
28
|
+
}
|