nibula 2.4.2 → 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 +29 -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/src/frontend/scss/pages/404.scss +6 -21
- package/src/frontend/scss/pages/homepage.scss +1 -1
- package/tools/res/templates/template.scss +1 -1
- 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/Backend.md
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
# Backend
|
|
2
|
-
|
|
3
|
-
Nibula ships **two interchangeable backends** — PHP and Node.js. You pick one
|
|
4
|
-
when you scaffold a project with `nib new`, and **only that one is copied into
|
|
5
|
-
your project**: a Node project contains no PHP files and vice versa. Shared,
|
|
6
|
-
backend-agnostic files (SQL migrations, `.htaccess`, `web.config`) are always
|
|
7
|
-
included.
|
|
8
|
-
|
|
9
|
-
Both provide the same REST API: same routing, same `Response` envelope, same
|
|
10
|
-
`X-Api-Key` auth, same CORS model, same rate limiter. Only the syntax differs.
|
|
11
|
-
|
|
12
|
-
> **The examples below are in JavaScript (the Node backend).** If you chose PHP,
|
|
13
|
-
> everything works exactly the same way — same routing, same variables, same
|
|
14
|
-
> `Response` helper, same behaviour. Only the syntax differs.
|
|
15
|
-
|
|
16
|
-
For **where each backend can run** and how to deploy it, see `docs/Deploy.md`.
|
|
17
|
-
|
|
18
|
-
## Structure
|
|
19
|
-
|
|
20
|
-
The tree below shows both backends for reference; your project will have only
|
|
21
|
-
one side of each pair.
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
src/backend/
|
|
25
|
-
├── api/
|
|
26
|
-
│ ├── public/ # Endpoints accessible without an API key
|
|
27
|
-
│ └── protected/ # Endpoints requiring the X-Api-Key header
|
|
28
|
-
├── _core/ # Framework internals (routing, modules) — do not edit
|
|
29
|
-
│ ├── index.php # PHP front controller (PHP project)
|
|
30
|
-
│ ├── index.js # Node front controller + server (Node project)
|
|
31
|
-
│ ├── init.php / init.js
|
|
32
|
-
│ └── modules/ # Response, RateLimiter
|
|
33
|
-
├── database/
|
|
34
|
-
│ ├── Database.php # PDO singleton (PHP project)
|
|
35
|
-
│ ├── Database.js # mysql2 pool singleton (Node project)
|
|
36
|
-
│ └── migrations/ # shared
|
|
37
|
-
├── example.config.php / example.config.js # versioned template
|
|
38
|
-
└── config.php / config.js # generated on setup, never commit
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
> `config.php` / `config.js` are created automatically by `nib new` as a copy of
|
|
42
|
-
> the matching `example.config.*`, and are git-ignored so your secrets stay
|
|
43
|
-
> local. If `config.*` is missing (e.g. after a fresh clone), copy the example.
|
|
44
|
-
|
|
45
|
-
### Installing Composer packages (PHP)
|
|
46
|
-
|
|
47
|
-
Backend dependencies live in `src/backend/_core`, next to `composer.json`.
|
|
48
|
-
Install from there, not from the project root:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
cd src/backend/_core
|
|
52
|
-
composer require vendor/package
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
`_core/init.php` already requires Composer's autoloader, so an installed package
|
|
56
|
-
is usable in your endpoints straight away — there is no extra `require` to add.
|
|
57
|
-
|
|
58
|
-
Packages land in `src/backend/_core/vendor/`, which is git-ignored. After a fresh
|
|
59
|
-
clone that folder is missing and the backend won't start at all: run
|
|
60
|
-
`composer install` from `src/backend/_core` to restore it.
|
|
61
|
-
|
|
62
|
-
## How routing works
|
|
63
|
-
|
|
64
|
-
The file path inside `api/` maps directly to the URL. The `public` / `protected`
|
|
65
|
-
folder does **not** appear in the URL — it only decides whether the `X-Api-Key`
|
|
66
|
-
check applies:
|
|
67
|
-
|
|
68
|
-
- `api/public/example-public` → `/api/example-public` (no key)
|
|
69
|
-
- `api/protected/example-protected` → `/api/example-protected` (requires key)
|
|
70
|
-
|
|
71
|
-
Subfolders **do** appear: `api/public/users/list` → `/api/users/list`.
|
|
72
|
-
|
|
73
|
-
Extra URL segments become route parameters, resolved from the deepest match
|
|
74
|
-
backwards: `/api/posts/42` looks for `posts/42` first, then falls back to
|
|
75
|
-
`posts` with `42` as a parameter.
|
|
76
|
-
|
|
77
|
-
Every endpoint receives:
|
|
78
|
-
|
|
79
|
-
| Field | Description |
|
|
80
|
-
|---|---|
|
|
81
|
-
| `method` | HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) |
|
|
82
|
-
| `requestParams` | Extra URL segments (e.g. `/api/posts/42` → `['42']`) |
|
|
83
|
-
|
|
84
|
-
The Node handler also gets `query`, `body` (parsed JSON), `rawBody`, `headers`,
|
|
85
|
-
`config`, `req`, `res`.
|
|
86
|
-
|
|
87
|
-
> ⚠️ If two files share the same path — one in `public/`, one in `protected/` —
|
|
88
|
-
> the public one wins, so the endpoint ends up **without** authentication. Don't
|
|
89
|
-
> duplicate names across the two folders.
|
|
90
|
-
|
|
91
|
-
## Creating an endpoint
|
|
92
|
-
|
|
93
|
-
Create a file anywhere inside `api/public/` or `api/protected/`. For protected
|
|
94
|
-
endpoints the API-key check runs automatically before your file does.
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
module.exports = ({ method, requestParams, Response }) => {
|
|
98
|
-
if (method !== 'GET') Response.error('Method not allowed', 405);
|
|
99
|
-
const id = requestParams[0] ? parseInt(requestParams[0], 10) : null;
|
|
100
|
-
Response.success({ id });
|
|
101
|
-
};
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## The Response helper
|
|
105
|
-
|
|
106
|
-
Same envelope in both backends.
|
|
107
|
-
|
|
108
|
-
```js
|
|
109
|
-
Response.success(data, code); // default 200
|
|
110
|
-
Response.error(message, code, details); // default 400
|
|
111
|
-
Response.noContent(); // 204
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Shapes:
|
|
115
|
-
|
|
116
|
-
- success → `{ "status": "success", "data": ... }`
|
|
117
|
-
- error → `{ "status": "error", "message": "...", "code": ... }` (+ optional `details`)
|
|
118
|
-
|
|
119
|
-
## Configuration
|
|
120
|
-
|
|
121
|
-
`config.php` / `config.js` work like a `.env` file: they hold secrets and
|
|
122
|
-
environment settings that stay local and out of version control. Same keys in
|
|
123
|
-
both, PHP-array vs JS-object syntax.
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
module.exports = {
|
|
127
|
-
// Default key for protected endpoints that don't have a specific key in CUSTOM_ENDPOINT_KEYS
|
|
128
|
-
GENERAL_API_KEY: 'DEFAULT_KEY',
|
|
129
|
-
|
|
130
|
-
// If you want to restrict access to protected endpoints to specific clients, define custom keys per endpoint.
|
|
131
|
-
// For subfolder endpoints, use the relative path ('subfolder/endpoint')
|
|
132
|
-
CUSTOM_ENDPOINT_KEYS: {
|
|
133
|
-
'subfolder/example-protected': 'custom-key',
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
GENERAL_ALLOWED_ORIGINS: [
|
|
137
|
-
'*',
|
|
138
|
-
// 'https://example.com',
|
|
139
|
-
],
|
|
140
|
-
|
|
141
|
-
CUSTOM_ENDPOINT_ORIGINS: {
|
|
142
|
-
'subfolder/example-protected': ['https://app.example.com'],
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
// Database configuration
|
|
146
|
-
DB_HOST: '127.0.0.1',
|
|
147
|
-
DB_NAME: 'example_db',
|
|
148
|
-
DB_USER: 'root',
|
|
149
|
-
DB_PASS: '',
|
|
150
|
-
|
|
151
|
-
// Environment: 'production' hides error details; anything else = debug.
|
|
152
|
-
APP_ENV: 'production',
|
|
153
|
-
};
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### API keys
|
|
157
|
-
|
|
158
|
-
`GENERAL_API_KEY` is the fallback for all protected endpoints.
|
|
159
|
-
`CUSTOM_ENDPOINT_KEYS` assigns a different key to a specific endpoint, keyed by
|
|
160
|
-
its relative path (`'subfolder/endpoint'`).
|
|
161
|
-
|
|
162
|
-
> ⚠️ The key travels in the `X-Api-Key` header on every request. Use it only for
|
|
163
|
-
> server-to-server calls over HTTPS. Never embed it in frontend code, where it
|
|
164
|
-
> would be publicly visible.
|
|
165
|
-
|
|
166
|
-
### CORS
|
|
167
|
-
|
|
168
|
-
Mirrors the API-key model: `GENERAL_ALLOWED_ORIGINS` is the default list,
|
|
169
|
-
`CUSTOM_ENDPOINT_ORIGINS` overrides it per endpoint using the same relative path.
|
|
170
|
-
|
|
171
|
-
Origins must be exact (scheme + host, no trailing slash). A matching `Origin` is
|
|
172
|
-
reflected in `Access-Control-Allow-Origin` with `Vary: Origin`. An empty list
|
|
173
|
-
sends no CORS header — the most restrictive setting; same-origin requests still
|
|
174
|
-
work. `'*'` as the only element allows any origin (not recommended for protected
|
|
175
|
-
endpoints).
|
|
176
|
-
|
|
177
|
-
Resolution order: `CUSTOM_ENDPOINT_ORIGINS[path]` if present, otherwise
|
|
178
|
-
`GENERAL_ALLOWED_ORIGINS`.
|
|
179
|
-
|
|
180
|
-
### Error verbosity
|
|
181
|
-
|
|
182
|
-
`APP_ENV` decides what an unhandled exception tells the client.
|
|
183
|
-
|
|
184
|
-
| Value | Response to a 500 |
|
|
185
|
-
|---|---|
|
|
186
|
-
| `'production'` (default) | `{"status":"error","message":"Internal server error","code":500}` |
|
|
187
|
-
| anything else | the real exception message, plus `stack` (Node) or `file` and `line` (PHP) |
|
|
188
|
-
|
|
189
|
-
On PHP it does one extra thing: `'production'` also turns off `display_errors`
|
|
190
|
-
and `error_reporting`, so a stray warning can't be printed before the JSON and
|
|
191
|
-
corrupt the response body.
|
|
192
|
-
|
|
193
|
-
Set it to something like `'development'` while building, and back to
|
|
194
|
-
`'production'` before you publish. Missing key means `'production'`.
|
|
195
|
-
|
|
196
|
-
> This is a config key, **not** an environment variable. Setting `APP_ENV` in a
|
|
197
|
-
> shell or in a systemd unit has no effect — both backends read it from
|
|
198
|
-
> `config.js` / `config.php` only.
|
|
199
|
-
|
|
200
|
-
## Database
|
|
201
|
-
|
|
202
|
-
Both backends expose a connection singleton reading the same config —
|
|
203
|
-
`database/Database.js` (a `mysql2` pool) or `database/Database.php` (a PDO
|
|
204
|
-
singleton).
|
|
205
|
-
|
|
206
|
-
```js
|
|
207
|
-
const pool = Database.getInstance();
|
|
208
|
-
const [rows] = await pool.execute(sql, params);
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
`mysql2` is installed at scaffold time and loaded lazily, so the backend boots
|
|
212
|
-
fine without a database.
|
|
213
|
-
|
|
214
|
-
## Pre-built endpoints
|
|
215
|
-
|
|
216
|
-
| Route | Method | Description |
|
|
217
|
-
|---|---|---|
|
|
218
|
-
| `/api/example-public` | `GET` | Example endpoint requiring no key |
|
|
219
|
-
| `/api/example-protected` | `GET` | Example endpoint requiring `X-Api-Key` |
|
package/docs/Components.md
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
# Nunjucks (HTML) Components
|
|
2
|
-
|
|
3
|
-
## What is Nunjucks
|
|
4
|
-
|
|
5
|
-
Nunjucks (`.njk`) is an HTML file that supports logic like variables, `if` statements, and `for` loops. It can extend a base layout and include other `.njk` components
|
|
6
|
-
|
|
7
|
-
## Create a component
|
|
8
|
-
|
|
9
|
-
Create a new `.njk` file anywhere inside `src/frontend/components/`. You can organize them into subfolders freely
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
src/frontend/components/
|
|
13
|
-
├── global/
|
|
14
|
-
│ ├── header.njk
|
|
15
|
-
│ └── footer.njk
|
|
16
|
-
├── not-found.njk
|
|
17
|
-
├── welcome.njk
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Include a component
|
|
21
|
-
|
|
22
|
-
Components are included in the page that renders them. Open the page's file in `src/frontend/routes/` and write the includes in its body
|
|
23
|
-
|
|
24
|
-
### example-page.njk <small>(`src/frontend/routes/`)</small>
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
---
|
|
28
|
-
title: "examplePage"
|
|
29
|
-
permalink: "/example-page/"
|
|
30
|
-
layout: base.njk
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
{% include "example-component-1.njk" %}
|
|
34
|
-
{% include "subfolder/example-component-2.njk" %}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Components render in the order you list them. If a component lives in a subfolder, specify the relative path accordingly
|
|
38
|
-
|
|
39
|
-
Paths are resolved from `src/frontend/components/`, so you never write that part — `"welcome.njk"`, not `"components/welcome.njk"`
|
|
40
|
-
|
|
41
|
-
> ⚠️ If you move or delete a component, update every route that includes it or the build will fail
|
|
42
|
-
|
|
43
|
-
Writing HTML directly in the route works too, and is perfectly fine for a short page. Components are the recommendation when there is something to reuse or when a page grows past a screenful — not a rule
|
|
44
|
-
|
|
45
|
-
## Nest components
|
|
46
|
-
|
|
47
|
-
A component can include other components. This is useful for breaking complex sections into smaller, reusable pieces.
|
|
48
|
-
|
|
49
|
-
### exampleComponent.njk
|
|
50
|
-
```html
|
|
51
|
-
<section class="hero">
|
|
52
|
-
{% include "hero/hero-title.njk" %}
|
|
53
|
-
{% include "hero/hero-button.njk" %}
|
|
54
|
-
</section>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
> The same path rules apply: if the included component is in a subfolder, specify the full relative path.
|
|
58
|
-
|
|
59
|
-
## Markdown files
|
|
60
|
-
|
|
61
|
-
### What is Markdown
|
|
62
|
-
|
|
63
|
-
Markdown (`.md`) is a way to write formatted text without HTML tags. You write
|
|
64
|
-
`**bold**` instead of `<strong>bold</strong>`, and a line starting with `-`
|
|
65
|
-
becomes a list item. For a page that is mostly text — an article, a privacy
|
|
66
|
-
policy, a changelog — it is much faster than writing the markup by hand.
|
|
67
|
-
|
|
68
|
-
### Write the file
|
|
69
|
-
|
|
70
|
-
Create a `.md` file in `src/frontend/components/`, next to your `.njk` ones.
|
|
71
|
-
|
|
72
|
-
#### article.md <small>(`src/frontend/components/`)</small>
|
|
73
|
-
|
|
74
|
-
```markdown
|
|
75
|
-
## Section title
|
|
76
|
-
|
|
77
|
-
Regular paragraph text. **Bold** and *italic* work as usual.
|
|
78
|
-
|
|
79
|
-
- First item
|
|
80
|
-
- Second item
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Show it in a page
|
|
84
|
-
|
|
85
|
-
Open the page's file in `src/frontend/routes/` and add this line to its body:
|
|
86
|
-
|
|
87
|
-
```html
|
|
88
|
-
<article class="markdown-body">
|
|
89
|
-
{% renderFile "article.md" | markdownPath, { site: site }, "md" %}
|
|
90
|
-
</article>
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Four parts to it:
|
|
94
|
-
|
|
95
|
-
| Part | What it does |
|
|
96
|
-
|---|---|
|
|
97
|
-
| `class="markdown-body"` | the wrapper that applies the Markdown styling — without it your content renders unstyled |
|
|
98
|
-
| `renderFile` | turns the Markdown into HTML and puts it in the page |
|
|
99
|
-
| `markdownPath` | fills in the `src/frontend/components/` part of the path for you |
|
|
100
|
-
| `{ site: site }` | hands the file your site settings — see below |
|
|
101
|
-
| `"md"` | specifies that the rendering should be done as Markdown, ignoring the njk engine associated by default with the file extension |
|
|
102
|
-
|
|
103
|
-
Subfolders work the same way as with components:
|
|
104
|
-
`"legal/privacy.md" | markdownPath`
|
|
105
|
-
|
|
106
|
-
### Why `{ site: site }`
|
|
107
|
-
|
|
108
|
-
A `.md` file can use site values, exactly like a component:
|
|
109
|
-
|
|
110
|
-
```markdown
|
|
111
|
-
Welcome to {{ site.title }}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
But a Markdown file does not automatically see them. Anything the file needs has
|
|
115
|
-
to be listed in the curly braces:
|
|
116
|
-
|
|
117
|
-
```js
|
|
118
|
-
{% renderFile "article.md" | markdownPath, { site: site, pages: pages } %}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
If you forget, nothing breaks — the value simply comes out empty. So if a
|
|
122
|
-
`{{ site.something }}` disappears from your page, this is why.
|
|
123
|
-
|
|
124
|
-
### Extras you get for free
|
|
125
|
-
|
|
126
|
-
**Links to a section.** Every `##` and `###` heading gets an anchor, so you can
|
|
127
|
-
link straight to it: `yoursite.com/my-page/#section-title`.
|
|
128
|
-
|
|
129
|
-
**CSS classes.** Markdown produces plain HTML with no classes, so your framework's
|
|
130
|
-
styling doesn't reach it. Add a class in curly braces after the element:
|
|
131
|
-
|
|
132
|
-
```markdown
|
|
133
|
-
## Section title {.text-center}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
> ⚠️ If the `.md` file is missing or the name is misspelled, the build stops with
|
|
137
|
-
> an error. That is on purpose: silently skipping content you asked for is worse.
|
|
138
|
-
|
|
139
|
-
## Global components
|
|
140
|
-
|
|
141
|
-
Header and footer live in `src/frontend/components/global/` and are automatically included in every page via `base.njk`. Edit them to change the site-wide layout
|
|
142
|
-
|
|
143
|
-
## Custom layouts
|
|
144
|
-
|
|
145
|
-
`base.njk` is the default layout, but it isn't the only one you can have. Any
|
|
146
|
-
`.njk` file in `src/frontend/layouts/` is a layout, and each route picks its own.
|
|
147
|
-
|
|
148
|
-
The usual reason is a page that doesn't fit the standard shell: a landing page
|
|
149
|
-
with no header or footer, a full-screen login, a "coming soon" holding page.
|
|
150
|
-
|
|
151
|
-
Copy `base.njk`, rename it, and change only what you need — that way you keep the
|
|
152
|
-
head, the SEO tags and the CSS/JS wiring, which is the part you don't want to
|
|
153
|
-
rewrite:
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
src/frontend/layouts/
|
|
157
|
-
├── base.njk
|
|
158
|
-
└── custom.njk
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### custom.njk <small>(`src/frontend/layouts/`)</small>
|
|
162
|
-
|
|
163
|
-
Same as `base.njk`, without the two global includes:
|
|
164
|
-
|
|
165
|
-
```html
|
|
166
|
-
<body>
|
|
167
|
-
<main>
|
|
168
|
-
{{ content | safe }}
|
|
169
|
-
</main>
|
|
170
|
-
</body>
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Then point the route at it:
|
|
174
|
-
|
|
175
|
-
### landing.njk <small>(`src/frontend/routes/`)</small>
|
|
176
|
-
|
|
177
|
-
```js
|
|
178
|
-
---
|
|
179
|
-
title: "landing"
|
|
180
|
-
permalink: "/landing/"
|
|
181
|
-
layout: custom.njk
|
|
182
|
-
---
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Paths are resolved from `src/frontend/layouts/`, so you write `"custom.njk"`, not
|
|
186
|
-
`"layouts/custom.njk"` — the same rule as components.
|
|
187
|
-
|
|
188
|
-
> ⚠️ A layout you copy is a copy: a later fix to `base.njk` won't reach it. Keep
|
|
189
|
-
> the differences to the minimum, and check your custom layouts when you change
|
|
190
|
-
> something in the head.
|
|
191
|
-
|
|
192
|
-
## Site data in components
|
|
193
|
-
|
|
194
|
-
All values defined in `src/frontend/data/site.json` are globally available in every component via `{{ site.* }}`
|
|
195
|
-
|
|
196
|
-
### site.json <small>(`src/frontend/data/`)</small>
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"site_name": "Site name",
|
|
200
|
-
"title": "Site title",
|
|
201
|
-
"description": "Site description",
|
|
202
|
-
"keywords": "keyword1, keyword2, keyword3",
|
|
203
|
-
"domain": "yoursite.com",
|
|
204
|
-
"url": "https://yoursite.com",
|
|
205
|
-
"lang": "en",
|
|
206
|
-
"author": "Name and surname",
|
|
207
|
-
"logo": "/assets/brand/logo.svg",
|
|
208
|
-
"legal": {
|
|
209
|
-
"privacy": "",
|
|
210
|
-
"cookie": "",
|
|
211
|
-
"terms": "",
|
|
212
|
-
"copyright": {
|
|
213
|
-
"year": "2026",
|
|
214
|
-
"text": "All rights reserved."
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
`legal.privacy`, `legal.cookie` and `legal.terms` hold the URLs of your legal pages — the footer links to them. See **Head & SEO** DOC file for what every field does
|
|
221
|
-
|
|
222
|
-
### Usage in any `.njk` file
|
|
223
|
-
```html
|
|
224
|
-
<p>{{ site.title }}</p>
|
|
225
|
-
<a href="{{ site.legal.privacy }}">Privacy Policy</a>
|
|
226
|
-
<img src="{{ site.logo }}" alt="{{ site.title }}">
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
> In a `.md` file rendered with `renderFile`, these values only work if you passed
|
|
230
|
-
> `site` in the curly braces — see *Why `{ site: site }`* above.
|
|
231
|
-
|
|
232
|
-
## Your own data files
|
|
233
|
-
|
|
234
|
-
`site.json` isn't special: **any** `.json` file you drop in `src/frontend/data/` becomes a global variable, and the variable takes the name of the file.
|
|
235
|
-
|
|
236
|
-
Create `test.json`, put anything you want inside it, and every key is reachable as `test.yourKey` — no import, no configuration, no restart.
|
package/docs/Creating pages.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Creating Pages
|
|
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
|
-
The recommended way is via the **Assistant CLI**
|
|
6
|
-
|
|
7
|
-
## What gets created
|
|
8
|
-
For a page named `my-page`:
|
|
9
|
-
|
|
10
|
-
| File | Purpose |
|
|
11
|
-
|---|---|
|
|
12
|
-
| `src/frontend/routes/my-page.njk` | Template with front matter |
|
|
13
|
-
| `src/frontend/scss/pages/myPage.scss` | Imports framework + modules |
|
|
14
|
-
| `src/frontend/js/pages/myPage.js` | Imports JS/TS modules |
|
|
15
|
-
|
|
16
|
-
It also adds a stub entry in `src/frontend/data/pages.json` for the page's SEO and CDN links — fill it in as described in the **Head & SEO** DOC file.
|
|
17
|
-
|
|
18
|
-
## Adding content
|
|
19
|
-
|
|
20
|
-
The route is created empty, with two commented examples: one for including a
|
|
21
|
-
`.njk` component, one for rendering a `.md` file. Uncomment the one you need or
|
|
22
|
-
write your HTML directly in the body — see the **Components** DOC file.
|
|
23
|
-
|
|
24
|
-
## URL and title
|
|
25
|
-
|
|
26
|
-
The URL is the kebab-case name (`/my-page/`). The `title` in the front matter is camelCase (`myPage`) and is used internally to load the correct CSS and JS files, and to look up the page's record in `pages.json` — do not change it.
|
|
27
|
-
|
|
28
|
-
## Layout
|
|
29
|
-
|
|
30
|
-
`layout` decides the HTML skeleton the page is rendered into. New pages get `base.njk`, which brings the head, the SEO tags, the header and the footer.
|
|
31
|
-
|
|
32
|
-
A page that needs a different shell — a landing page with no header, for instance — points at a layout of its own. See **Components** DOC file, *Custom layouts*.
|
|
33
|
-
|
|
34
|
-
## Subpages (nested URLs)
|
|
35
|
-
|
|
36
|
-
To create a URL like `domain.it/about/team`, edit the `permalink` in `src/frontend/routes/team.njk` and add the parent segment before the final slash:
|
|
37
|
-
|
|
38
|
-
```js
|
|
39
|
-
---
|
|
40
|
-
title: "team"
|
|
41
|
-
permalink: "/about/team/"
|
|
42
|
-
layout: base.njk
|
|
43
|
-
---
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
The parent path (`about`) does **not** need to exist as a real page — it's just a URL prefix. Only the last segment (`team`) must match the filename and the `title` in the front matter.
|
|
47
|
-
|
|
48
|
-
| Goal URL | permalink value | File |
|
|
49
|
-
|---|---|---|
|
|
50
|
-
| `/team/` | `/team/` | `routes/team.njk` |
|
|
51
|
-
| `/about/team/` | `/about/team/` | `routes/team.njk` |
|
|
52
|
-
| `/company/about/team/` | `/company/about/team/` | `routes/team.njk` |
|