nibula 2.4.3 → 2.4.4
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 +24 -0
- package/README.md +82 -53
- package/package.json +7 -7
- package/src/frontend/components/global/footer.njk +1 -1
- package/src/frontend/components/global/header.njk +1 -1
- package/src/frontend/components/welcome.njk +1 -2
- package/src/frontend/data/site.json +5 -2
- package/src/frontend/indexing/llms.njk +2 -2
- package/src/frontend/layouts/base.njk +5 -4
- package/docs/Assistant CLI.md +0 -70
- package/docs/Backend.md +0 -219
- package/docs/Components.md +0 -236
- package/docs/Creating pages.md +0 -52
- package/docs/Deploy.md +0 -279
- package/docs/Head and SEO.md +0 -198
- package/docs/JavaScript.md +0 -127
- package/docs/Project structure.md +0 -66
- package/docs/Styling with SCSS.md +0 -147
package/docs/Head and SEO.md
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# Head & SEO
|
|
2
|
-
|
|
3
|
-
The `<head>` of an HTML page holds the information *about* the page rather than
|
|
4
|
-
its content: the title shown in the browser tab, the description search engines
|
|
5
|
-
display, the image that appears when someone shares the link. Nibula writes all
|
|
6
|
-
of it for you — you just fill in the values.
|
|
7
|
-
|
|
8
|
-
There are two files to fill in:
|
|
9
|
-
|
|
10
|
-
- **`src/frontend/data/site.json`** — settings for the whole site
|
|
11
|
-
- **`src/frontend/data/pages.json`** — settings for one page at a time
|
|
12
|
-
|
|
13
|
-
A page uses its own value when it has one, and falls back to the site-wide value
|
|
14
|
-
when it doesn't. So filling in `site.json` well means most pages need nothing.
|
|
15
|
-
|
|
16
|
-
## Site-wide settings
|
|
17
|
-
|
|
18
|
-
Everything in `site.json` is available anywhere in your templates as
|
|
19
|
-
`{{ site.something }}`.
|
|
20
|
-
|
|
21
|
-
```json
|
|
22
|
-
{
|
|
23
|
-
"site_name": "Site name",
|
|
24
|
-
"title": "Site title",
|
|
25
|
-
"description": "Site description",
|
|
26
|
-
"keywords": "keyword1, keyword2, keyword3",
|
|
27
|
-
"domain": "yoursite.com",
|
|
28
|
-
"url": "https://yoursite.com",
|
|
29
|
-
"lang": "en",
|
|
30
|
-
"author": "Name and surname",
|
|
31
|
-
"theme": "dark",
|
|
32
|
-
"theme_color": "#2a2150",
|
|
33
|
-
"logo": "/assets/brand/logo.svg",
|
|
34
|
-
"legal": {
|
|
35
|
-
"privacy": "",
|
|
36
|
-
"cookie": "",
|
|
37
|
-
"terms": "",
|
|
38
|
-
"copyright": {
|
|
39
|
-
"year": "2026",
|
|
40
|
-
"text": "Copyright text"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
| Field | What it's for |
|
|
47
|
-
|---|---|
|
|
48
|
-
| `site_name` | Your brand or project name |
|
|
49
|
-
| `title` | Default page title — used by any page that doesn't set its own |
|
|
50
|
-
| `description` | Default description — same idea |
|
|
51
|
-
| `keywords` | Default keywords — same idea |
|
|
52
|
-
| `domain` / `url` | Used to build full page addresses for search engines and social previews |
|
|
53
|
-
| `lang` | The language of your site (`en`, `it`, ...) |
|
|
54
|
-
| `author` | Your name |
|
|
55
|
-
| `theme` | Colour scheme of the site: `light` or `dark` |
|
|
56
|
-
| `theme_color` | Colour of the browser bar on phones — should match your theme |
|
|
57
|
-
| `logo` | Path to your logo, also used as the image in social previews |
|
|
58
|
-
| `legal.privacy` / `cookie` / `terms` | Addresses of your legal pages — the footer links to them |
|
|
59
|
-
| `legal.copyright.year` / `text` | The copyright line in the footer |
|
|
60
|
-
|
|
61
|
-
## Per-page settings
|
|
62
|
-
|
|
63
|
-
`pages.json` holds one entry per page, and the assistant creates it for you when
|
|
64
|
-
you add a page. Each entry is keyed by the page's `title` from its front matter —
|
|
65
|
-
the camelCase one.
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"examplePage": {
|
|
70
|
-
"seo": {
|
|
71
|
-
"title": "Example Page",
|
|
72
|
-
"description": "Description",
|
|
73
|
-
"keywords": "",
|
|
74
|
-
"noindex": false,
|
|
75
|
-
"canonical": ""
|
|
76
|
-
},
|
|
77
|
-
"cdn": {
|
|
78
|
-
"css": ["https://example.com/lib.min.css"],
|
|
79
|
-
"js": ["https://example.com/lib.min.js"]
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
| Field | What it's for | If you leave it empty |
|
|
86
|
-
|---|---|---|
|
|
87
|
-
| `seo.title` | The page's title, shown in the browser tab and in search results | Uses the site-wide `title` |
|
|
88
|
-
| `seo.description` | The short summary search engines show under the title | Uses the site-wide `description` |
|
|
89
|
-
| `seo.keywords` | Keywords for this page | Uses the site-wide `keywords` |
|
|
90
|
-
| `seo.noindex` | Set to `true` to ask search engines **not** to list this page | The page can be found normally |
|
|
91
|
-
| `seo.canonical` | The one official address of this page, if the same content is reachable at more than one URL | Worked out automatically |
|
|
92
|
-
| `cdn.css` / `cdn.js` | Extra stylesheets or scripts loaded from the internet, on this page only | Nothing extra is loaded |
|
|
93
|
-
|
|
94
|
-
> ⚠️ The assistant fills new entries with placeholder text like `"Description"`.
|
|
95
|
-
> Replace it — a page left that way tells search engines and AI crawlers that its
|
|
96
|
-
> description is literally "Description".
|
|
97
|
-
|
|
98
|
-
### How the fallback works
|
|
99
|
-
|
|
100
|
-
Site-wide values are defaults, not duplicates. You don't need to repeat them per
|
|
101
|
-
page. This is what the template actually does:
|
|
102
|
-
|
|
103
|
-
```njk
|
|
104
|
-
{{ pageData.seo.title or title or site.title }}
|
|
105
|
-
{{ pageData.seo.description or site.description }}
|
|
106
|
-
{{ pageData.seo.keywords or site.keywords }}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Read it as: use the page's value; if there isn't one, use the site's.
|
|
110
|
-
|
|
111
|
-
`noindex` and `canonical` work per-page only — there's no site-wide version,
|
|
112
|
-
because "hide the whole site from search" and "one address for the whole site"
|
|
113
|
-
aren't things you'd want.
|
|
114
|
-
|
|
115
|
-
## Theme
|
|
116
|
-
|
|
117
|
-
One value in `site.json` controls the colour scheme everywhere:
|
|
118
|
-
|
|
119
|
-
```html
|
|
120
|
-
<html data-theme="{{ site.theme }}" data-bs-theme="{{ site.theme }}">
|
|
121
|
-
<meta name="color-scheme" content="{{ site.theme }}">
|
|
122
|
-
<meta name="theme-color" content="{{ site.theme_color }}">
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
| What it sets | Why it's there |
|
|
126
|
-
|---|---|
|
|
127
|
-
| `data-theme` | Your own hook — target it in your SCSS to define theme colours |
|
|
128
|
-
| `data-bs-theme` | Bootstrap's dark mode switch. Harmlessly ignored with other frameworks |
|
|
129
|
-
| `color-scheme` | Standard CSS — makes scrollbars, form fields and autofill match your theme |
|
|
130
|
-
| `theme-color` | The colour of the browser bar on phones |
|
|
131
|
-
|
|
132
|
-
Keep `theme` and `theme_color` in agreement: a dark theme with a white
|
|
133
|
-
`theme_color` gives a white browser bar sitting on top of a dark page.
|
|
134
|
-
|
|
135
|
-
See the **Styling with SCSS** DOC file for how to hook your own colours to
|
|
136
|
-
`data-theme`.
|
|
137
|
-
|
|
138
|
-
## Favicon
|
|
139
|
-
|
|
140
|
-
The favicon is the small icon in the browser tab. The three tags are written
|
|
141
|
-
directly in `base.njk`. To change the icons, replace the files in
|
|
142
|
-
`src/frontend/assets/brand/` **keeping the same names**:
|
|
143
|
-
|
|
144
|
-
```html
|
|
145
|
-
<link rel="icon" type="image/svg+xml" href="{{ '/assets/brand/favicon.svg' | url }}">
|
|
146
|
-
<link rel="icon" type="image/png" sizes="32x32" href="{{ '/assets/brand/favicon-32.png' | url }}">
|
|
147
|
-
<link rel="apple-touch-icon" sizes="180x180" href="{{ '/assets/brand/apple-touch-icon.png' | url }}">
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
| File | What uses it |
|
|
151
|
-
|---|---|
|
|
152
|
-
| `favicon.svg` | Modern browsers — scales to any size |
|
|
153
|
-
| `favicon-32.png` | Older browsers and some crawlers |
|
|
154
|
-
| `apple-touch-icon.png` | The icon iOS uses when someone saves your site to their home screen. Must be 180×180 and **not** transparent — iOS turns transparency into black |
|
|
155
|
-
|
|
156
|
-
> ⚠️ Without `apple-touch-icon.png`, iOS uses a screenshot of your page as the
|
|
157
|
-
> home screen icon instead.
|
|
158
|
-
|
|
159
|
-
## Where all this is written
|
|
160
|
-
|
|
161
|
-
Everything above is produced by `src/frontend/layouts/base.njk`, which looks up
|
|
162
|
-
the current page's entry like this:
|
|
163
|
-
|
|
164
|
-
```njk
|
|
165
|
-
{% set pageKey = title %}
|
|
166
|
-
{% set pageData = pages[pageKey] %}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
You only need to edit `base.njk` for something the boilerplate doesn't cover — a
|
|
170
|
-
web font, an analytics snippet. For everything documented here, change the values
|
|
171
|
-
in `site.json` and `pages.json` instead.
|
|
172
|
-
|
|
173
|
-
> ⚠️ Paths in `base.njk` go through `| url`. That filter makes them work when the
|
|
174
|
-
> site is published in a subfolder rather than at the root of a domain — GitHub
|
|
175
|
-
> Pages being the common case. Remove it and every stylesheet and script breaks
|
|
176
|
-
> there.
|
|
177
|
-
|
|
178
|
-
## Files for search engines and AI
|
|
179
|
-
|
|
180
|
-
Three files are generated automatically and published with your site:
|
|
181
|
-
|
|
182
|
-
| File | What it's for | Reachable at |
|
|
183
|
-
|---|---|---|
|
|
184
|
-
| `llms.txt` | Describes your site and lists its pages, for AI models | `yoursite.com/llms.txt` |
|
|
185
|
-
| `robots.txt` | Tells search engines what they may and may not crawl | `yoursite.com/robots.txt` |
|
|
186
|
-
| `sitemap.xml` | Lists your pages so search engines find them all | `yoursite.com/sitemap.xml` |
|
|
187
|
-
|
|
188
|
-
They are built from templates in `src/frontend/indexing/`. `llms.txt` and
|
|
189
|
-
`sitemap.xml` build their page lists the same way: they go through every page and
|
|
190
|
-
leave out drafts, the 404 page, and anything marked `noindex`. Creating a page
|
|
191
|
-
with the assistant is enough for it to appear in both — there is no list to keep
|
|
192
|
-
up to date by hand.
|
|
193
|
-
|
|
194
|
-
To change the wording or the fixed parts, edit
|
|
195
|
-
`src/frontend/indexing/llms.njk` or `src/frontend/indexing/robots.njk`.
|
|
196
|
-
|
|
197
|
-
> These three files must stay publicly reachable. If you block them in your server
|
|
198
|
-
> config, search engines and AI models can't read them.
|
package/docs/JavaScript.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# JavaScript
|
|
2
|
-
|
|
3
|
-
> Examples use JavaScript, but everything applies equally to TypeScript. The only difference is the file extension (`.ts` instead of `.js`), that imports do **not** include the extension, and that paths use `src/frontend/ts/` instead of `src/frontend/js/`.
|
|
4
|
-
|
|
5
|
-
## Page JS
|
|
6
|
-
|
|
7
|
-
Each page has its own JS entry point in `src/frontend/js/pages/`, bundled and minified by esbuild and loaded automatically by `base.njk`.
|
|
8
|
-
|
|
9
|
-
Import only what the page needs.
|
|
10
|
-
|
|
11
|
-
### examplePage.js <small>(`src/frontend/js/pages/`)</small>
|
|
12
|
-
|
|
13
|
-
```js
|
|
14
|
-
import '../global.js';
|
|
15
|
-
|
|
16
|
-
// import { initExampleModule } from '../modules/exampleModule.js';
|
|
17
|
-
|
|
18
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
19
|
-
// initExampleModule();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Page logic here
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Global JS
|
|
26
|
-
|
|
27
|
-
Some code has to run on every page: a header menu, a theme toggle, a cookie banner. Repeating it in every page entry point means you'll eventually forget it on one of them, and the bug only shows up on that single page.
|
|
28
|
-
|
|
29
|
-
That's what `global.js` is for. It lives in `src/frontend/js/`, every page entry point imports it, and it takes care of running the shared modules.
|
|
30
|
-
|
|
31
|
-
### global.js <small>(`src/frontend/js/`)</small>
|
|
32
|
-
|
|
33
|
-
```js
|
|
34
|
-
// import { initExampleModule } from './modules/exampleModule.js';
|
|
35
|
-
|
|
36
|
-
function initGlobal() {
|
|
37
|
-
// initExampleModule();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Global logic here
|
|
41
|
-
|
|
42
|
-
// Do not touch
|
|
43
|
-
// This instruction starts global.js itself
|
|
44
|
-
document.addEventListener('DOMContentLoaded', initGlobal);
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Pages import it without curly braces, since there is nothing to export — the module runs on its own as soon as it's part of the bundle:
|
|
48
|
-
|
|
49
|
-
```js
|
|
50
|
-
import '../global.js';
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Note the difference in import paths. A page entry point sits inside `js/pages/`, so it reaches a module with `'../modules/exampleModule.js'`. `global.js` sits directly in `js/`, one level up, so the same module is `'./modules/exampleModule.js'`.
|
|
54
|
-
|
|
55
|
-
### A concrete example: the header menu
|
|
56
|
-
|
|
57
|
-
A responsive header has a burger button that opens the navigation on small screens. The header is included in `base.njk`, so it's on every page — a textbook case for `global.js`.
|
|
58
|
-
|
|
59
|
-
Write the behaviour as a normal module:
|
|
60
|
-
|
|
61
|
-
### header.js <small>(`src/frontend/js/modules/`)</small>
|
|
62
|
-
```js
|
|
63
|
-
export function initHeader() {
|
|
64
|
-
const toggle = document.querySelector('.menu-toggle');
|
|
65
|
-
const menu = document.querySelector('.menu');
|
|
66
|
-
|
|
67
|
-
if (!toggle || !menu) return;
|
|
68
|
-
|
|
69
|
-
toggle.addEventListener('click', () => {
|
|
70
|
-
menu.classList.toggle('is-open');
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Then wire it up once, in `global.js`:
|
|
76
|
-
|
|
77
|
-
```js
|
|
78
|
-
import { initHeader } from './modules/header.js';
|
|
79
|
-
|
|
80
|
-
function initGlobal() {
|
|
81
|
-
initHeader();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Do not touch
|
|
85
|
-
// This instruction starts global.js itself
|
|
86
|
-
document.addEventListener('DOMContentLoaded', initGlobal);
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
The burger now works on every page, and no page entry point had to change. Adding another global behaviour later is two lines: one import, one call inside `initGlobal()`.
|
|
90
|
-
|
|
91
|
-
The early `return` matters: if a page has no header, the module does nothing instead of throwing an error that would stop your other scripts.
|
|
92
|
-
|
|
93
|
-
### Global or page module?
|
|
94
|
-
|
|
95
|
-
Use `global.js` for behaviour tied to something present on every page — anything included in `base.njk`, essentially.
|
|
96
|
-
|
|
97
|
-
Keep it in the page entry point when only one or two pages need it. Everything imported by `global.js` ends up in *every* page bundle, so a heavy module used by a single page belongs in that page instead.
|
|
98
|
-
|
|
99
|
-
## Modules
|
|
100
|
-
|
|
101
|
-
Modules live in `src/frontend/js/modules/`. Modules that interact with the DOM must be called inside `DOMContentLoaded`; others can be called anywhere.
|
|
102
|
-
|
|
103
|
-
## Adding a module
|
|
104
|
-
|
|
105
|
-
Create a new `.js` file in `src/frontend/js/modules/`. Subfolders are allowed.
|
|
106
|
-
|
|
107
|
-
Use ESM syntax — esbuild handles the bundling:
|
|
108
|
-
|
|
109
|
-
### exampleModule.js <small>(`src/frontend/js/modules/`)</small>
|
|
110
|
-
|
|
111
|
-
```js
|
|
112
|
-
export function exampleModule() {
|
|
113
|
-
// Module logic here
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
Then import it in the pages that need it:
|
|
118
|
-
|
|
119
|
-
```js
|
|
120
|
-
import { exampleModule } from '../modules/exampleModule.js';
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
In TypeScript, omit the extension:
|
|
124
|
-
|
|
125
|
-
```ts
|
|
126
|
-
import { exampleModule } from '../modules/exampleModule';
|
|
127
|
-
```
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Project Structure
|
|
2
|
-
|
|
3
|
-
> Examples use JavaScript, but everything applies equally to TypeScript. The only difference is the file extension (`.ts` instead of `.js`), that imports do **not** include the extension, and that paths use `src/frontend/ts/` instead of `src/frontend/js/`.
|
|
4
|
-
|
|
5
|
-
Nibula ships a fixed layout so you always know where to put your hands. Inside these folders you're free to organize as you like — subfolders in `components/`, `modules/` and `api/` are all fair game.
|
|
6
|
-
|
|
7
|
-
## The tree
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
your-project/
|
|
11
|
-
├── .eleventy.js # Eleventy configuration
|
|
12
|
-
├── nginx.conf # nginx site file
|
|
13
|
-
├── package.json
|
|
14
|
-
├── out/ # Build output — never edit, never commit
|
|
15
|
-
└── src/
|
|
16
|
-
├── backend/ # REST API — see docs/Backend.md
|
|
17
|
-
└── frontend/
|
|
18
|
-
├── assets/ # Images, fonts, brand files
|
|
19
|
-
│ └── brand/ # Favicons, logo etc
|
|
20
|
-
├── components/ # Reusable .njk fragments and .md content
|
|
21
|
-
│ └── global/ # Header and footer, included in every page
|
|
22
|
-
├── data/ # site.json and pages.json
|
|
23
|
-
├── hosting/ # .htaccess and web.config
|
|
24
|
-
├── indexing/ # llms, robots and sitemap templates
|
|
25
|
-
├── js/ # global.js, modules/, pages/
|
|
26
|
-
├── layouts/ # base.njk — the HTML skeleton every page extends
|
|
27
|
-
├── routes/ # One file per page
|
|
28
|
-
└── scss/ # _root.scss, _global.scss, modules/, pages/
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Where things happen
|
|
32
|
-
|
|
33
|
-
| I want to... | Go to |
|
|
34
|
-
|---|---|
|
|
35
|
-
| Add a page | `nib cli` → creates the files in `routes/`, `scss/pages/`, `js/pages/` |
|
|
36
|
-
| Write the content of a page | `routes/` |
|
|
37
|
-
| Build a reusable block of markup | `components/` |
|
|
38
|
-
| Write long prose in Markdown | `components/` — see docs/Components.md |
|
|
39
|
-
| Change the header or footer | `components/global/` |
|
|
40
|
-
| Style one page | `scss/pages/` |
|
|
41
|
-
| Style every page | `scss/_global.scss` |
|
|
42
|
-
| Define a variable used across the site | `scss/_root.scss` |
|
|
43
|
-
| Run a script on one page | `js/pages/` |
|
|
44
|
-
| Run a script everywhere | `js/global.js` |
|
|
45
|
-
| Change the site name, URL, author | `data/site.json` |
|
|
46
|
-
| Change a page's SEO | `data/pages.json` |
|
|
47
|
-
| Edit the HTML `<head>` | `layouts/base.njk` |
|
|
48
|
-
| Give one page a different skeleton | `layouts/` — add your own, see docs/Components.md |
|
|
49
|
-
| Add an API endpoint | `backend/api/` |
|
|
50
|
-
|
|
51
|
-
## Two folders worth a note
|
|
52
|
-
|
|
53
|
-
**`out/`** is generated by every build. Editing anything in it means losing the change the next time you run `nib run` or `nib build`. Always edit the source in `src/` — including `.htaccess` and `web.config`, whose sources live in `src/frontend/hosting/`.
|
|
54
|
-
|
|
55
|
-
**`data/`** feeds the build but is never published: it holds the full page map, including pages you marked `noindex`, so it stays out of the output on purpose.
|
|
56
|
-
|
|
57
|
-
## What you can rearrange
|
|
58
|
-
|
|
59
|
-
Subfolders are allowed wherever content is yours to organize:
|
|
60
|
-
|
|
61
|
-
- `components/` — nest as deep as you like; includes take the path relative to `components/`, and so does the `markdownPath` filter
|
|
62
|
-
- `scss/modules/` and `js/modules/` — same idea, remember to update the relative import paths
|
|
63
|
-
- `layouts/` — extra layouts alongside `base.njk`; routes pick one by filename
|
|
64
|
-
- `backend/api/public/` and `protected/` — subfolders become part of the URL
|
|
65
|
-
|
|
66
|
-
The folders in the tree above are the part to leave alone: paths are wired into `.eleventy.js`, the build scripts and the assistant, so renaming one breaks the build.
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# Styling with SCSS
|
|
2
|
-
|
|
3
|
-
## Page CSS
|
|
4
|
-
|
|
5
|
-
Each page has its own SCSS entry point in `src/frontend/scss/pages/`
|
|
6
|
-
|
|
7
|
-
It must contain `_root.scss` + any other module that you need and its own specific css rules
|
|
8
|
-
|
|
9
|
-
`_root.scss` uses `@use` to enable namespaced access (`root.$var`); other modules use `@import` as they don't expose variables.
|
|
10
|
-
|
|
11
|
-
### examplePage.scss <small>(`src/frontend/scss/pages/`)</small>
|
|
12
|
-
```scss
|
|
13
|
-
//==========================
|
|
14
|
-
// CSS MODULES IMPORTS
|
|
15
|
-
//==========================
|
|
16
|
-
|
|
17
|
-
@use "../root" as root;
|
|
18
|
-
|
|
19
|
-
@import "../global";
|
|
20
|
-
|
|
21
|
-
//==========================
|
|
22
|
-
// PAGE CUSTOM CSS RULES
|
|
23
|
-
//==========================
|
|
24
|
-
|
|
25
|
-
body {
|
|
26
|
-
background-color: root.$primary;
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Global Variables
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
### _root.scss <small>(`src/frontend/scss/`)</small>
|
|
35
|
-
```scss
|
|
36
|
-
$header-height: 10vh;
|
|
37
|
-
|
|
38
|
-
// Usage example (in any other file):
|
|
39
|
-
header {
|
|
40
|
-
height: root.$header-height;
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Scss modules
|
|
45
|
-
|
|
46
|
-
You can create your custom css modules by creating a new `.scss` file in `src/frontend/scss/modules/` (the name of the file must start with `_`)
|
|
47
|
-
|
|
48
|
-
You can create subfolders if you want to refactor the structure, but be sure to update the relative paths in the pages that import them
|
|
49
|
-
|
|
50
|
-
### _yourModule.scss <small>(`src/frontend/scss/modules/subfolder/`)</small>
|
|
51
|
-
```scss
|
|
52
|
-
@use '../../root' as root;
|
|
53
|
-
|
|
54
|
-
@import '../../global';
|
|
55
|
-
|
|
56
|
-
body {
|
|
57
|
-
background-color: root.$primary;
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### examplePage.scss
|
|
62
|
-
```scss
|
|
63
|
-
@import "../modules/subfolder/yourModule";
|
|
64
|
-
|
|
65
|
-
// This page will now inherit the body tag rules
|
|
66
|
-
// If the same property is declared in both, the last imported one wins
|
|
67
|
-
body {
|
|
68
|
-
color: root.$dark;
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Pre-existing modules
|
|
73
|
-
|
|
74
|
-
| File | Purpose |
|
|
75
|
-
|---|---|
|
|
76
|
-
| `_typography.scss` | Font rules |
|
|
77
|
-
| `_header.scss` | Header styles |
|
|
78
|
-
| `_footer.scss` | Footer styles |
|
|
79
|
-
| `_mobile.scss` | Media query rules |
|
|
80
|
-
| `_animations.scss` | Keyframe animations (`fade-in`, `spin`) |
|
|
81
|
-
| `_markdown.scss` | Styling for Markdown rendered with `renderFile`. See **Components** DOC file |
|
|
82
|
-
|
|
83
|
-
> If you don't use Markdown files as components, comment its import from `_global.scss`.
|
|
84
|
-
|
|
85
|
-
## CSS Framework
|
|
86
|
-
|
|
87
|
-
Some of the most popular css frameworks that supports scss with modules are already installed in `node_modules`
|
|
88
|
-
|
|
89
|
-
You can choose one or none of them (more than 1 works, but you may get in various conflicts)
|
|
90
|
-
|
|
91
|
-
To enable/disable them you have to modify 3 files around the project by just commenting them
|
|
92
|
-
|
|
93
|
-
### 1. _global.scss <small>(`src/frontend/scss/`)</small>
|
|
94
|
-
```scss
|
|
95
|
-
@import "modules/frameworks/bootstrap";
|
|
96
|
-
// @import "modules/frameworks/bulma";
|
|
97
|
-
// @import "modules/frameworks/foundation";
|
|
98
|
-
// @import "modules/frameworks/uikit";
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### 2. base.njk <small>(`src/frontend/layouts/`)</small>
|
|
102
|
-
|
|
103
|
-
```html
|
|
104
|
-
{# Bootstrap JS #}
|
|
105
|
-
<script src="{{ '/js/bootstrap.bundle.min.js' | url }}" defer></script>
|
|
106
|
-
|
|
107
|
-
{# Foundation JS #}
|
|
108
|
-
{# <script src="{{ '/js/foundation.min.js' | url }}" defer></script> #}
|
|
109
|
-
|
|
110
|
-
{# UIkit JS #}
|
|
111
|
-
{# <script src="{{ '/js/uikit.min.js' | url }}" defer></script> #}
|
|
112
|
-
{# <script src="{{ '/js/uikit-icons.min.js' | url }}" defer></script> #}
|
|
113
|
-
|
|
114
|
-
{# Bulma — no JS needed #}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### 3. .eleventy.js <small>(project root)</small>
|
|
118
|
-
|
|
119
|
-
```javascript
|
|
120
|
-
eleventyConfig.addPassthroughCopy({
|
|
121
|
-
// Bootstrap
|
|
122
|
-
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js": "js/bootstrap.bundle.min.js",
|
|
123
|
-
"node_modules/bootstrap-icons/font/fonts": "css/fonts",
|
|
124
|
-
|
|
125
|
-
// Foundation
|
|
126
|
-
// "node_modules/foundation-sites/dist/js/foundation.min.js": "js/foundation.min.js",
|
|
127
|
-
|
|
128
|
-
// UIkit
|
|
129
|
-
// "node_modules/uikit/dist/js/uikit.min.js": "js/uikit.min.js",
|
|
130
|
-
// "node_modules/uikit/dist/js/uikit-icons.min.js": "js/uikit-icons.min.js",
|
|
131
|
-
|
|
132
|
-
// Bulma — CSS only, no JS passthrough needed
|
|
133
|
-
});
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
> ⚠️ Changes to `.eleventy.js` are not picked up while the dev server is running — restart it.
|
|
137
|
-
|
|
138
|
-
> These three files are set up for you when you pick a framework during `nib new`. You only need to edit them by hand if you change your mind later.
|
|
139
|
-
|
|
140
|
-
### Reducing bundle size
|
|
141
|
-
|
|
142
|
-
To reduce the bundle size, open the corresponding framework file (`src/frontend/scss/modules/frameworks/`) and comment out any modules you don't need
|
|
143
|
-
|
|
144
|
-
```scss
|
|
145
|
-
@import "bootstrap/scss/card"; // Cards
|
|
146
|
-
@import "bootstrap/scss/carousel"; // Carousel
|
|
147
|
-
```
|