nimbi-cms 1.0.0
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/LICENSE.md +21 -0
- package/README.md +501 -0
- package/dist/nimbi-cms.cjs.js +1316 -0
- package/dist/nimbi-cms.css +1 -0
- package/dist/nimbi-cms.es.js +8338 -0
- package/dist/nimbi-cms.js +1316 -0
- package/package.json +69 -0
- package/src/index.d.ts +362 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Abel Vázquez Montoro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: nimbiCMS
|
|
3
|
+
author: Abel Vázquez Montoro
|
|
4
|
+
date: 2026-03-16
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<img src="./assets/logo.png" alt="logo" style="height:256px;width:256px;" />
|
|
8
|
+
|
|
9
|
+
# nimbiCMS
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/nimbi-cms) [](https://www.jsdelivr.com/package/npm/nimbi-cms) [](https://bundlephobia.com/package/nimbi-cms)
|
|
12
|
+
|
|
13
|
+
Lightweight, lightspeed, SEO-first client-side CMS
|
|
14
|
+
|
|
15
|
+
## The project
|
|
16
|
+
|
|
17
|
+
NimbiCMS is a client-side CMS for static sites that requires **no database, no server build step, and no backend**, just a bunch of Markdown or HTML pages and a minimalistic setup
|
|
18
|
+
|
|
19
|
+
Just drop your Markdown files into a folder, serve the site (GitHub Pages, S3, etc.), and the client will crawl the content, render Markdown to HTML, hook links, manage slugs and anchors, maintain navigation and search functionalities, and update SEO tags on the fly. All that while being compliant, fast and accesible!
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
Editing content via the GitHub web editor works too—just save and refresh to see updates.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Client-side rendering of [GitHub‑flavored Markdown](https://github.github.com/gfm/) via [marked.js](https://marked.js.org/), no need for site compilation
|
|
28
|
+
- No Jekyll, no Hugo, no CI at all
|
|
29
|
+
- Perfect for static servers (GitHub Pages, S3, etc.)
|
|
30
|
+
- Optional client-side search box built from headings and excerpts (enabled by default).
|
|
31
|
+
- Reading time estimation
|
|
32
|
+
- Code is organized into small modules to ease maintenance and testing.
|
|
33
|
+
- Sticky per-page, dynamically generated TOC.
|
|
34
|
+
- [Bulma](https://bulma.io/)‑based UI components.
|
|
35
|
+
- Runtime updates for SEO, Open Graph and Twitter meta tags.
|
|
36
|
+
- Markdown headers management ([yaml_metadata_block by pandoc](https://pandoc.org/MANUAL.html#extension-yaml_metadata_block))
|
|
37
|
+
- Lazily loads images by default, while heuristically marking above‑the‑fold images as eager.
|
|
38
|
+
- Image preview modal with zoom controls, wheel zoom, drag pan, double-click to zoom, and touch pinch support.
|
|
39
|
+
- Syntax highlighting using [highlight.js](https://highlightjs.org/) — languages are auto-registered when detected.
|
|
40
|
+
- Simple theming (light/dark), Bulma and hightlight.js customization options.
|
|
41
|
+
- Simplified deliverables: regardless all the dynamic imports, the bundle is kept in one JS file and one CSS file
|
|
42
|
+
- Bundle is compact size
|
|
43
|
+
- JS file: 240.15 kB, gzipped 70.09 kB (for UMD bundle)
|
|
44
|
+
- CSS file: 409.43 kB, gzipped 41.30 kB (includes Bulma)
|
|
45
|
+
- All the heavy work is managed by web workers to avoid hogging the main thread
|
|
46
|
+
- Pluggable architecture through the available hooks
|
|
47
|
+
- Fully typed and [documented](docs/README.md)
|
|
48
|
+
- [MIT licensed](LICENSE.md)
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
npm run build
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For development with live reload:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm run dev
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## How to use
|
|
64
|
+
|
|
65
|
+
### Basic HTML example
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<!doctype html>
|
|
69
|
+
<html><head><meta charset="utf-8">
|
|
70
|
+
<script src="/dist/nimbi-cms.js"></script>
|
|
71
|
+
<link rel="preload" href="/dist/nimbi-cms.css" as="style" onload="this.rel='stylesheet'">
|
|
72
|
+
<noscript><link rel="stylesheet" href="/dist/nimbi-cms.css"></noscript>
|
|
73
|
+
</head><body>
|
|
74
|
+
<div id="app" style="height:100vh"></div>
|
|
75
|
+
<script>
|
|
76
|
+
nimbiCMS.initCMS({ el: '#app' })
|
|
77
|
+
</script>
|
|
78
|
+
</body></html>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Bundle formats
|
|
82
|
+
|
|
83
|
+
Examples showing how to consume each shipped bundle format produced by the build.
|
|
84
|
+
|
|
85
|
+
- UMD (browser global)
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<!-- include the UMD bundle and CSS -->
|
|
89
|
+
<link rel="stylesheet" href="/dist/nimbi-cms.css">
|
|
90
|
+
<script src="/dist/nimbi-cms.js"></script>
|
|
91
|
+
<div id="app"></div>
|
|
92
|
+
<script>
|
|
93
|
+
// UMD exposes a global `nimbiCMS` object
|
|
94
|
+
nimbiCMS.initCMS({ el: '#app' })
|
|
95
|
+
</script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- ESM (modern bundlers / `<script type="module">`)
|
|
99
|
+
|
|
100
|
+
```html
|
|
101
|
+
<script type="module">
|
|
102
|
+
import initCMS from '/dist/nimbi-cms.es.js'
|
|
103
|
+
initCMS({ el: '#app' })
|
|
104
|
+
</script>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- CJS (Node / CommonJS consumers)
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
const { initCMS } = require('./dist/nimbi-cms.cjs.js')
|
|
111
|
+
initCMS({ el: '#app' })
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Notes:**
|
|
115
|
+
|
|
116
|
+
- The UMD build is a single, self-contained `dist/nimbi-cms.js` file that exposes the public API on the `nimbiCMS` global.
|
|
117
|
+
- The ES build is `dist/nimbi-cms.es.js` and is ideal for modern bundlers and `<script type="module">` usage.
|
|
118
|
+
- The CJS build is `dist/nimbi-cms.cjs.js` for CommonJS consumers.
|
|
119
|
+
- CSS is always shipped as `dist/nimbi-cms.css` and should be loaded alongside the script for styling. For performance optimization, it's advised to preload the CSS file like:
|
|
120
|
+
|
|
121
|
+
```html
|
|
122
|
+
<link rel="preload" href="/dist/nimbi-cms.css" as="style" onload="this.rel='stylesheet'">
|
|
123
|
+
<noscript><link rel="stylesheet" href="/dist/nimbi-cms.css"></noscript>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Content Workflow
|
|
127
|
+
|
|
128
|
+
Drop `.md` and/or `.html` files into your content directory. No build step is necessary; a static server that serves the files is sufficient.
|
|
129
|
+
|
|
130
|
+
> When loading `.html` files, only the `body` block is parsed. All the code in `head` is overriden, so, if you want some specific styling or script being run for that page, add them to `body`. Check `assets/playground.html` source for an example
|
|
131
|
+
|
|
132
|
+
**Required files**
|
|
133
|
+
|
|
134
|
+
- `_home.md` — required by default. You can override this with the `homePage` option to use a different `.md` or `.html` file as the home page.
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
initCMS({ el: '#app', homePage: 'index.html' })
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- `_navigation.md` — renders into the navbar; use Markdown links. Example nav markup:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
[Home](_home.md)
|
|
144
|
+
[Blog](blog.md)
|
|
145
|
+
[About](about.md)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- `_404.md` — optional fallback for 404 responses. When the server responds to a requested `.md` path with an HTML document (e.g., an SPA fallback serving `index.html`), the CMS treats that as a missing markdown page and will attempt to load `/_404.md` from the configured content base so a proper 404 page can be rendered instead of the site's index HTML.
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
initCMS({ el: '#app', notFoundPage: '_404.md' })
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Links are converted to hash‑based navigation (`?page=…`), preserving anchors and URL passed parameters
|
|
155
|
+
|
|
156
|
+
## Options
|
|
157
|
+
|
|
158
|
+
`initCMS(InitOptions)` mounts the CMS into a page. The table below summarizes the supported `InitOptions`. This options can be overrrided using URL parameters with the same name.
|
|
159
|
+
|
|
160
|
+
### Core
|
|
161
|
+
|
|
162
|
+
| Option | Type | Default | Description |
|
|
163
|
+
|---|---:|:---:|---|
|
|
164
|
+
| `el` | `string` \ `Element` | required | CSS selector or DOM element used as the mount target. |
|
|
165
|
+
| `contentPath` | `string` | `/content` | URL path to the content folder serving `.md`/`.html` files; normalized to a relative path with trailing slash. |
|
|
166
|
+
| `allowUrlPathOverrides` | `boolean` | `false` | Opt-in: when `true`, `contentPath`, `homePage`, and `notFoundPage` may be overridden from the page URL (validated). |
|
|
167
|
+
|
|
168
|
+
### Indexing and Search
|
|
169
|
+
|
|
170
|
+
| Option | Type | Default | Description |
|
|
171
|
+
|---|---:|:---:|---|
|
|
172
|
+
| `searchIndex` | `boolean` | `true` | Enable the runtime search index and render a search box. |
|
|
173
|
+
| `searchIndexMode` | `'eager'` \| `'lazy'` | `'eager'` | When to build the index (`'eager'` on init, `'lazy'` on first query). |
|
|
174
|
+
| `indexDepth` | `1 \| 2 \| 3` | `1` | How deep headings are indexed (H1, H2, H3). |
|
|
175
|
+
| `noIndexing` | `string[]` | — | Paths (relative) to exclude from discovery and indexing. |
|
|
176
|
+
| `skipRootReadme` | `boolean` | `false` | When `true`, skip link discovery inside a repository-root `README.md`. |
|
|
177
|
+
|
|
178
|
+
### Routing and Pages
|
|
179
|
+
|
|
180
|
+
| Option | Type | Default | Description |
|
|
181
|
+
|---|---:|:---:|---|
|
|
182
|
+
| `homePage` | `string` | `'_home.md'` | Basename for the site home page (`.md` or `.html`). |
|
|
183
|
+
| `notFoundPage` | `string` | `'_404.md'` | Basename for the not-found page (`.md` or `.html`). |
|
|
184
|
+
|
|
185
|
+
### Styling and Theming
|
|
186
|
+
|
|
187
|
+
| Option | Type | Default | Description |
|
|
188
|
+
|---|---:|:---:|---|
|
|
189
|
+
| `defaultStyle` | `'light'` \| `'dark'` \| `'system'` | `'light'` | Initial UI theme. |
|
|
190
|
+
| `bulmaCustomize` | `string` | `'none'` | `'none'` (bundled), `'local'` (load `<contentPath>/bulma.css`) or a Bulmaswatch theme name to load remotely. |
|
|
191
|
+
| `navbarLogo` | `string` | `'favicon'` | Small site logo placed at the leftmost position of the navbar. Supported values: `none`, `favicon` (uses PNG favicon when available), a path or URL to an image, `copy-first` (use first image from `homePage`), and `move-first` (use first image from `homePage` and remove it from the rendered page). |
|
|
192
|
+
|
|
193
|
+
### Localization
|
|
194
|
+
|
|
195
|
+
| Option | Type | Default | Description |
|
|
196
|
+
|---|---:|:---:|---|
|
|
197
|
+
| `lang` | `string` | — | UI language code (e.g. `en`, `de`). |
|
|
198
|
+
| `l10nFile` | `string \| null` | `null` | Path to a JSON localization file (relative paths resolve against the page). |
|
|
199
|
+
| `availableLanguages` | `string[]` | — | When set, treats a leading path segment as a language code and maps slugs per-language. |
|
|
200
|
+
|
|
201
|
+
### Caching and Performance
|
|
202
|
+
|
|
203
|
+
| Option | Type | Default | Description |
|
|
204
|
+
|---|---:|:---:|---|
|
|
205
|
+
| `cacheTtlMinutes` | `number` | `5` | TTL for slug-resolution cache entries (minutes). Set `0` to disable expiration. |
|
|
206
|
+
| `cacheMaxEntries` | `number` | — | Maximum entries in the router resolution cache. |
|
|
207
|
+
| `crawlMaxQueue` | `number` | `1000` | Upper bound on directories queued during breadth-first crawl (0 disables the guard). |
|
|
208
|
+
|
|
209
|
+
### Advanced and Extensions
|
|
210
|
+
|
|
211
|
+
| Option | Type | Default | Description |
|
|
212
|
+
|---|---:|:---:|---|
|
|
213
|
+
| `markdownExtensions` | `Array<object>` | — | `marked`-style extension/plugin objects registered at init via `addMarkdownExtension()`. |
|
|
214
|
+
| `markdownPaths` | `string[]` | — | Optional host-provided list of markdown paths used by slug resolution/search. |
|
|
215
|
+
|
|
216
|
+
## API
|
|
217
|
+
|
|
218
|
+
The `nimbi-cms` package exports a small set of helpers in addition to the default `initCMS` export. These are available as named imports in ESM and as properties on the `nimbiCMS` global in UMD builds.
|
|
219
|
+
|
|
220
|
+
For a complete listing of exported symbols and TypeScript types, see [the documentation](docs/README.md).
|
|
221
|
+
|
|
222
|
+
> **Note:** the default export (`initCMS`) and the `default` alias are intentionally excluded from the list below.
|
|
223
|
+
|
|
224
|
+
### Version
|
|
225
|
+
|
|
226
|
+
- `getVersion()` — returns a `Promise<string>` that resolves to the shipped package version (e.g. `"0.1.0"`). Useful for displaying build metadata or detecting whether the loaded bundle matches a deployed backend.
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
import { getVersion } from 'nimbi-cms'
|
|
230
|
+
getVersion().then(v => console.log('nimbiCMS version', v))
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Hooks (extension points)
|
|
234
|
+
|
|
235
|
+
These helpers let you hook into internal rendering and navigation without forking the source.
|
|
236
|
+
|
|
237
|
+
- `addHook(name, fn)` — register a callback for one of the supported hook points (`'onPageLoad' | 'onNavBuild' | 'transformHtml'`).
|
|
238
|
+
- `onPageLoad(fn)` — fired after a page is rendered and inserted into the DOM. Useful for analytics, adding UI enhancements, or triggering client-side behavior once content is available.
|
|
239
|
+
- `onNavBuild(fn)` — fired after the navigation HTML is constructed but before it is attached to the document; ideal for mutating nav links, injecting controls, or adding a search input.
|
|
240
|
+
- `transformHtml(fn)` — fired just before an article node is appended; gives you access to the generated DOM element and HTML string so you can alter structure, add attributes, or instrument the output.
|
|
241
|
+
- `runHooks(name, ctx)` — programmatically invoke hook callbacks (useful in tests or when you want to replay a lifecycle event after manually inserting content).
|
|
242
|
+
- `_clearHooks()` — clear all registered hooks. This is mainly intended for unit tests so each test can start with a clean hook slate.
|
|
243
|
+
|
|
244
|
+
```js
|
|
245
|
+
import { onPageLoad, onNavBuild, transformHtml } from 'nimbi-cms'
|
|
246
|
+
|
|
247
|
+
onPageLoad(({ pagePath, article }) => {
|
|
248
|
+
console.log('page rendered', pagePath)
|
|
249
|
+
// e.g. initialize custom widgets inside the loaded article
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
onNavBuild(({ navWrap }) => {
|
|
253
|
+
const btn = document.createElement('button')
|
|
254
|
+
btn.textContent = 'Toggle theme'
|
|
255
|
+
btn.onclick = () => setStyle('dark')
|
|
256
|
+
navWrap.querySelector('.navbar-end')?.appendChild(btn)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
transformHtml((html, article) => {
|
|
260
|
+
// Add a data attribute to every rendered page
|
|
261
|
+
article.dataset.nimbiRendered = 'true'
|
|
262
|
+
})
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Theming & Styling helpers
|
|
266
|
+
|
|
267
|
+
- `ensureBulma(bulmaCustomize?, pageDir?)` — ensures Bulma is loaded. Pass `'local'` to load a local `bulma.css` (looks in the page directory and `/${pageDir}/bulma.css`), or pass a Bulmaswatch theme name (e.g. `'flatly'`) to load from unpkg.
|
|
268
|
+
- `setStyle(style)` — switch between light/dark/system modes by updating `data-theme` and the `is-dark` class on the document. This matches the behavior of the built-in theme toggle.
|
|
269
|
+
- `setThemeVars(vars)` — apply a set of CSS custom properties (e.g. `{ "--primary": "#06c" }`) on the document root for runtime theming without rebuilding.
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
import { ensureBulma, setStyle, setThemeVars } from 'nimbi-cms'
|
|
273
|
+
|
|
274
|
+
// Load a Bulmaswatch theme from unpkg
|
|
275
|
+
ensureBulma('flatly')
|
|
276
|
+
|
|
277
|
+
// Or load a local bulma.css (useful for self-hosted overrides)
|
|
278
|
+
ensureBulma('local', './content/')
|
|
279
|
+
|
|
280
|
+
setStyle('dark')
|
|
281
|
+
setThemeVars({ primary: '#06c', 'font-family': 'system-ui' })
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Localization helpers
|
|
285
|
+
|
|
286
|
+
- `t(key, ...args)` — translate a UI string key using the currently loaded locale dictionary. Supports parameter substitution like `t('helloUser', 'Alice')`.
|
|
287
|
+
- `loadL10nFile(url)` — fetch and merge a JSON localization file into the current dictionary. Does not automatically rerender UI (useful for on-demand language packs).
|
|
288
|
+
- `setLang(code)` — switch the UI language at runtime (e.g. `'en'`, `'de'`). This updates internal strings and affects slug resolution when `availableLanguages` is configured.
|
|
289
|
+
|
|
290
|
+
```js
|
|
291
|
+
import { t, loadL10nFile, setLang } from 'nimbi-cms'
|
|
292
|
+
|
|
293
|
+
// Dynamic translation
|
|
294
|
+
console.log(t('navigation'))
|
|
295
|
+
|
|
296
|
+
// Load an external translations file
|
|
297
|
+
await loadL10nFile('/i18n/l10n.json')
|
|
298
|
+
setLang('de')
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Code highlighting helpers
|
|
302
|
+
|
|
303
|
+
- `registerLanguage(name, modulePath)` — dynamically register a `highlight.js` language. Useful to lazy-load rarely used languages from a CDN.
|
|
304
|
+
- `loadSupportedLanguages()` — preload the supported languages map used by the on-demand language loader.
|
|
305
|
+
- `observeCodeBlocks(root)` — scan a DOM subtree and apply syntax highlighting to code blocks using the currently registered languages.
|
|
306
|
+
- `setHighlightTheme(name, { useCdn })` — switch the theme used by `highlight.js` (optionally fetch the CSS from CDN when `useCdn=true`).
|
|
307
|
+
- `SUPPORTED_HLJS_MAP` — map of supported highlight.js language identifiers (useful for building language selection UIs).
|
|
308
|
+
- `BAD_LANGUAGES` — list of languages that should not be auto-registered (usually because they are unsupported or conflict with browser file types).
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
import { registerLanguage, observeCodeBlocks, setHighlightTheme } from 'nimbi-cms'
|
|
312
|
+
|
|
313
|
+
registerLanguage('r', 'https://unpkg.com/highlight.js/lib/languages/r.js')
|
|
314
|
+
observeCodeBlocks(document.body)
|
|
315
|
+
setHighlightTheme('monokai', { useCdn: true })
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Examples
|
|
319
|
+
|
|
320
|
+
This very site is running **nimbiCMS**!
|
|
321
|
+
|
|
322
|
+
The files used to do so, apart from the bundle, are:
|
|
323
|
+
* index.html
|
|
324
|
+
* README.md (this file)
|
|
325
|
+
* LICENSE.md
|
|
326
|
+
* _navigation.md
|
|
327
|
+
* _404.md
|
|
328
|
+
* assets/playground.html
|
|
329
|
+
|
|
330
|
+
## Theming and Customization
|
|
331
|
+
|
|
332
|
+
Bulma is bundled by default. To alter styles at runtime, use
|
|
333
|
+
`bulmaCustomize` with `'local'` or a Bulmaswatch theme name:
|
|
334
|
+
|
|
335
|
+
```js
|
|
336
|
+
initCMS({ el: '#app', contentPath: './content', bulmaCustomize: 'flatly' })
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
For build‑time custom Bulma, replace the import in `src/nimbi-cms.js` with
|
|
340
|
+
your compiled CSS and rebuild.
|
|
341
|
+
|
|
342
|
+
Light/dark toggling is managed via `defaultStyle` or `setStyle()`; highlight
|
|
343
|
+
colors can be changed with `setHighlightTheme()` (CDN load if `useCdn=true`).
|
|
344
|
+
|
|
345
|
+
## Localization
|
|
346
|
+
|
|
347
|
+
- `lang` option forces a UI language (short code, e.g. `en`, `de`).
|
|
348
|
+
- `l10nFile` may point to a JSON file of translations; relative paths resolve
|
|
349
|
+
against the page directory.
|
|
350
|
+
- Built‑in defaults live in `DEFAULT_L10N`; loaded files merge on top and fall
|
|
351
|
+
back to English.
|
|
352
|
+
|
|
353
|
+
To localize content (e.g. `content/en/` and `content/fr/`), point `contentPath`
|
|
354
|
+
at the desired language directory (for example, `contentPath: './content/en/'`).
|
|
355
|
+
The `lang` option only affects UI strings, not which content directory is used.
|
|
356
|
+
|
|
357
|
+
Example:
|
|
358
|
+
|
|
359
|
+
```js
|
|
360
|
+
// initial render (English content + UI)
|
|
361
|
+
initCMS({ el: '#app', contentPath: './content/en/', lang: 'en', availableLanguages: ['en','fr'] })
|
|
362
|
+
|
|
363
|
+
// later (French content + UI). This typically requires re-initializing the
|
|
364
|
+
// CMS or reloading the page with the new configuration.
|
|
365
|
+
initCMS({ el: '#app', contentPath: './content/fr/', lang: 'fr', availableLanguages: ['en','fr'] })
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
After initialization you can also change only the UI language at any time by
|
|
369
|
+
calling the exported `setLang(code)` helper. This updates internal state so
|
|
370
|
+
subsequent calls to `t()` return strings from the new dictionary.
|
|
371
|
+
|
|
372
|
+
> Note: `setLang()` does **not** reload or re-initialize the CMS; it only
|
|
373
|
+
> affects UI strings and the slug resolution logic when `availableLanguages` is
|
|
374
|
+
> configured. To switch content folders (e.g. `content/en/` → `content/fr/`),
|
|
375
|
+
> re-run `initCMS()` with a different `contentPath` (and `availableLanguages`).
|
|
376
|
+
|
|
377
|
+
Example translation file:
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
{
|
|
381
|
+
"de": { "navigation": "Navigation", "onThisPage": "Auf dieser Seite" }
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Usage:
|
|
386
|
+
|
|
387
|
+
```js
|
|
388
|
+
// contentPath is optional
|
|
389
|
+
initCMS({ el: '#app', l10nFile: '/i18n/l10n.json', lang: 'de' })
|
|
390
|
+
|
|
391
|
+
// later, switch to French at runtime
|
|
392
|
+
import { setLang } from 'nimbi-cms'
|
|
393
|
+
setLang('fr')
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
### Runtime path sanitization
|
|
398
|
+
|
|
399
|
+
To reduce the risk of accidental exposure or path traversal on static hosts,
|
|
400
|
+
the client sanitizes and normalizes runtime path options. Important
|
|
401
|
+
behaviour changes:
|
|
402
|
+
|
|
403
|
+
- `contentPath`, `homePage`, and `notFoundPage` are not accepted from the
|
|
404
|
+
page URL query string by default. These values may be provided programmatically
|
|
405
|
+
via the `initCMS()` `options` object only.
|
|
406
|
+
- When the host page explicitly opts in by passing `allowUrlPathOverrides: true`
|
|
407
|
+
to `initCMS()`, the library will consider URL query string overrides. Even
|
|
408
|
+
in that mode the values are validated and unsafe values are rejected.
|
|
409
|
+
|
|
410
|
+
Sanitization rules applied client-side:
|
|
411
|
+
|
|
412
|
+
- `contentPath`: must be a non-empty string, must not contain `..` segments,
|
|
413
|
+
must not be an absolute URL (no `protocol://`), must not start with `//`,
|
|
414
|
+
and must not be an absolute filesystem path (leading `/` or Windows drive
|
|
415
|
+
prefix). The value is normalized to a relative path with a trailing slash.
|
|
416
|
+
- `homePage` / `notFoundPage`: must be a simple basename (no slashes), only
|
|
417
|
+
contain letters, numbers, dot, underscore or hyphen, and must end with
|
|
418
|
+
`.md` or `.html`. Example safe names: `index.html`, `_home.md`.
|
|
419
|
+
|
|
420
|
+
If an unsafe value is detected the library will throw a `TypeError` when
|
|
421
|
+
initializing. Unit tests were added to cover the common misuse cases
|
|
422
|
+
(`tests/init.sanitization.test.js`) and the existing URL-override tests
|
|
423
|
+
ensure the default behaviour (ignoring URL-provided paths) remains safe.
|
|
424
|
+
|
|
425
|
+
If you need an advanced opt-in for integration tests or unusual hosting
|
|
426
|
+
environments, use `allowUrlPathOverrides: true` with caution and only when
|
|
427
|
+
you control the embedding page and the static host configuration.
|
|
428
|
+
|
|
429
|
+
### Opt-in usage example (cautious)
|
|
430
|
+
|
|
431
|
+
If you really need URL-driven overrides (for example in an integration test
|
|
432
|
+
or a special controlled embed scenario), you must enable them explicitly in
|
|
433
|
+
script code — they cannot be enabled from the URL itself. Only do this when
|
|
434
|
+
you control both the embedding page and the static host's content layout.
|
|
435
|
+
|
|
436
|
+
UMD example (bundle exposes `nimbiCMS`):
|
|
437
|
+
|
|
438
|
+
```html
|
|
439
|
+
<script>
|
|
440
|
+
// Only enable in trusted environments
|
|
441
|
+
nimbiCMS.initCMS({ el: '#app', allowUrlPathOverrides: true })
|
|
442
|
+
</script>
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
ES module example:
|
|
446
|
+
|
|
447
|
+
```js
|
|
448
|
+
import initCMS from 'nimbi-cms'
|
|
449
|
+
|
|
450
|
+
// Only enable in trusted environments where the host page is controlled
|
|
451
|
+
initCMS({ el: '#app', allowUrlPathOverrides: true })
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
> Note: enabling `allowUrlPathOverrides` still runs client-side validation; if an unsafe value is supplied the call to `initCMS()` will throw a `TypeError`. Prefer passing `contentPath`, `homePage`, and `notFoundPage` directly in the `options` object from secure script code rather than relying on URL query parameters.
|
|
455
|
+
|
|
456
|
+
## Available Bulmaswatch themes
|
|
457
|
+
|
|
458
|
+
The list of available Bulma themes is
|
|
459
|
+
|
|
460
|
+
> default, cerulean, cosmo, cyborg, darkly, flatly, journal, litera, lumen, lux, materia, minty, nuclear, pulse, sandstone, simplex, slate, solar, spacelab, superhero, united, yeti.
|
|
461
|
+
|
|
462
|
+
See previews at
|
|
463
|
+
<https://jenil.github.io/bulmaswatch/> and load via `bulmaCustomize` option or `ensureBulma` method.
|
|
464
|
+
|
|
465
|
+
Keep in mind that some themes do not play well with certain color schemas.
|
|
466
|
+
|
|
467
|
+
## Using with GitHub Pages and the GitHub file editor
|
|
468
|
+
|
|
469
|
+
Nimbi CMS works well with GitHub Pages and the built-in GitHub web file editor. Minimal steps:
|
|
470
|
+
|
|
471
|
+
- Enable GitHub Pages for the repository (Settings → Pages) and choose the branch/folder you want to publish (e.g., `gh-pages` or `main` / `/docs`).
|
|
472
|
+
- Ensure your published site serves the built `dist` assets (upload `dist/` to the chosen branch or use a build step / GitHub Action to publish).
|
|
473
|
+
- Place your content under a folder (default: `content/`) or set `contentPath` when calling `initCMS()` to point somewhere else.
|
|
474
|
+
|
|
475
|
+
Editing content via the GitHub web editor:
|
|
476
|
+
|
|
477
|
+
1. Open the repository on [GitHub](https://github.com) and navigate to the `content/` folder (or your chosen `contentPath`).
|
|
478
|
+
2. Click any `.md` file, then click the pencil icon to edit the file in the browser.
|
|
479
|
+
3. Make changes and commit them directly to the branch. The published site will receive the updates on the next Pages build (or immediately if you host the `dist` on the same branch).
|
|
480
|
+
4. Refresh the site to see the updated content. Nimbi CMS loads content at runtime, so browser refresh shows the latest files.
|
|
481
|
+
|
|
482
|
+
Tips:
|
|
483
|
+
- Add or update `content/_navigation.md` to control the navigation bar; the nav is re-built when pages are crawled.
|
|
484
|
+
- If you publish `dist/` separately (for example to `gh-pages`), consider a GitHub Action to build and push `dist/` automatically from `main`.
|
|
485
|
+
|
|
486
|
+
> Security note: Avoid exposing sensitive paths via URL query options; do not allow untrusted runtime overrides for `contentPath`, `homePage`, or `notFoundPage` unless you validate them server- or build-side.
|
|
487
|
+
|
|
488
|
+
## Troubleshooting
|
|
489
|
+
|
|
490
|
+
### Content not loading / 404 pages
|
|
491
|
+
- Verify `contentPath` is correct and matches the directory containing your `.md` files.
|
|
492
|
+
- Ensure your static server is serving those files (a 404 is often because the content folder isn’t published or the path is wrong).
|
|
493
|
+
- If you’re using `homePage`/`notFoundPage`, confirm those files exist and are reachable (the default is `_home.md` and `_404.md`).
|
|
494
|
+
|
|
495
|
+
### Styles not appearing / Bulma missing
|
|
496
|
+
- Ensure `dist/nimbi-cms.css` is loaded alongside `dist/nimbi-cms.js`.
|
|
497
|
+
- If using `bulmaCustomize: 'local'`, confirm `bulma.css` exists in the content path or at `/bulma.css`.
|
|
498
|
+
- If using a Bulmaswatch theme, verify the theme name is correct (see `Available Bulmaswatch themes`).
|
|
499
|
+
|
|
500
|
+
### Scripts failing / no mount element
|
|
501
|
+
- Make sure the mount element exists (`<div id="app"></div>`) and `initCMS({ el: '#app' })` uses the correct selector.
|