@terrymooreii/sia 2.1.9 → 2.1.10
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/docs/README.md +39 -0
- package/docs/template-reference.md +29 -0
- package/lib/assets.js +77 -0
- package/lib/build.js +6 -1
- package/lib/config.js +4 -0
- package/lib/content.js +10 -2
- package/package.json +1 -1
- package/themes/_shared/includes/custom-assets-css.njk +7 -0
- package/themes/_shared/includes/custom-assets-js.njk +7 -0
- package/themes/developer/layouts/base.njk +2 -0
- package/themes/developer/pages/index.njk +1 -1
- package/themes/developer/pages/tag.njk +1 -1
- package/themes/magazine/layouts/base.njk +2 -0
- package/themes/magazine/pages/tag.njk +1 -1
- package/themes/main/layouts/base.njk +2 -0
- package/themes/main/pages/tags.njk +1 -1
- package/themes/minimal/layouts/base.njk +2 -0
package/docs/README.md
CHANGED
|
@@ -121,8 +121,47 @@ pagination:
|
|
|
121
121
|
server:
|
|
122
122
|
port: 3000
|
|
123
123
|
showDrafts: false
|
|
124
|
+
|
|
125
|
+
assets:
|
|
126
|
+
css: [] # Custom CSS files (paths relative to root)
|
|
127
|
+
js: [] # Custom JavaScript files (paths relative to root)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Custom CSS and JavaScript
|
|
131
|
+
|
|
132
|
+
You can inject custom CSS and JavaScript files into your theme by defining them in `_config.yml`:
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
assets:
|
|
136
|
+
css:
|
|
137
|
+
- custom/styles.css
|
|
138
|
+
- vendor/library.css
|
|
139
|
+
js:
|
|
140
|
+
- custom/script.js
|
|
141
|
+
- vendor/analytics.js
|
|
124
142
|
```
|
|
125
143
|
|
|
144
|
+
Files are specified as paths relative to your project root. During build, CSS files are copied to `dist/styles/` and JavaScript files to `dist/scripts/`, preserving directory structure. Custom CSS is injected after theme styles (allowing overrides), and JavaScript is injected before the closing `</body>` tag.
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
```yaml
|
|
148
|
+
assets:
|
|
149
|
+
css:
|
|
150
|
+
- assets/custom.css
|
|
151
|
+
- vendor/prism.css
|
|
152
|
+
js:
|
|
153
|
+
- assets/analytics.js
|
|
154
|
+
- vendor/prism.js
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This will:
|
|
158
|
+
- Copy `assets/custom.css` → `dist/styles/assets/custom.css`
|
|
159
|
+
- Copy `vendor/prism.css` → `dist/styles/vendor/prism.css`
|
|
160
|
+
- Copy `assets/analytics.js` → `dist/scripts/assets/analytics.js`
|
|
161
|
+
- Copy `vendor/prism.js` → `dist/scripts/vendor/prism.js`
|
|
162
|
+
|
|
163
|
+
And inject them into all pages automatically.
|
|
164
|
+
|
|
126
165
|
## Static Assets
|
|
127
166
|
|
|
128
167
|
Sia automatically copies static assets during the build process. You can place static files in any of these locations:
|
|
@@ -107,6 +107,35 @@ Array of all tags sorted by count (most used first):
|
|
|
107
107
|
</ul>
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
### `customAssets`
|
|
111
|
+
|
|
112
|
+
Custom CSS and JavaScript files defined in `_config.yml`:
|
|
113
|
+
|
|
114
|
+
| Property | Type | Description |
|
|
115
|
+
|----------|------|-------------|
|
|
116
|
+
| `customAssets.css` | array | Array of CSS file paths (relative to output root) |
|
|
117
|
+
| `customAssets.js` | array | Array of JavaScript file paths (relative to output root) |
|
|
118
|
+
|
|
119
|
+
**Note:** Custom assets are automatically injected into all theme base layouts via shared includes (`custom-assets-css.njk` and `custom-assets-js.njk`). You typically don't need to access this variable directly unless creating custom layouts.
|
|
120
|
+
|
|
121
|
+
**Example:**
|
|
122
|
+
|
|
123
|
+
```nunjucks
|
|
124
|
+
{# Manually inject custom CSS #}
|
|
125
|
+
{% if customAssets and customAssets.css %}
|
|
126
|
+
{% for css in customAssets.css %}
|
|
127
|
+
<link rel="stylesheet" href="{{ css | url }}">
|
|
128
|
+
{% endfor %}
|
|
129
|
+
{% endif %}
|
|
130
|
+
|
|
131
|
+
{# Manually inject custom JavaScript #}
|
|
132
|
+
{% if customAssets and customAssets.js %}
|
|
133
|
+
{% for js in customAssets.js %}
|
|
134
|
+
<script src="{{ js | url }}"></script>
|
|
135
|
+
{% endfor %}
|
|
136
|
+
{% endif %}
|
|
137
|
+
```
|
|
138
|
+
|
|
110
139
|
---
|
|
111
140
|
|
|
112
141
|
## Page Context Variables
|
package/lib/assets.js
CHANGED
|
@@ -200,6 +200,82 @@ export function copyStaticAssets(config) {
|
|
|
200
200
|
return totalCopied;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Copy custom CSS and JavaScript files defined in config
|
|
205
|
+
*
|
|
206
|
+
* @param {object} config - Site configuration
|
|
207
|
+
* @returns {object} Object with css and js arrays of output paths
|
|
208
|
+
*/
|
|
209
|
+
export function copyCustomAssets(config) {
|
|
210
|
+
const customAssets = {
|
|
211
|
+
css: [],
|
|
212
|
+
js: []
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
if (!config.assets) {
|
|
216
|
+
return customAssets;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const outputStylesDir = join(config.outputDir, 'styles');
|
|
220
|
+
const outputScriptsDir = join(config.outputDir, 'scripts');
|
|
221
|
+
|
|
222
|
+
// Copy CSS files
|
|
223
|
+
if (Array.isArray(config.assets.css) && config.assets.css.length > 0) {
|
|
224
|
+
for (const cssPath of config.assets.css) {
|
|
225
|
+
const srcPath = join(config.rootDir, cssPath);
|
|
226
|
+
|
|
227
|
+
if (!existsSync(srcPath)) {
|
|
228
|
+
console.warn(`⚠️ Custom CSS file not found: ${cssPath}`);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Preserve directory structure in output
|
|
233
|
+
// e.g., custom/styles.css -> dist/styles/custom/styles.css
|
|
234
|
+
const relativePath = cssPath.startsWith('/') ? cssPath.slice(1) : cssPath;
|
|
235
|
+
const destPath = join(outputStylesDir, relativePath);
|
|
236
|
+
|
|
237
|
+
copyFile(srcPath, destPath);
|
|
238
|
+
|
|
239
|
+
// Store output path for template injection (relative to output root)
|
|
240
|
+
const outputPath = `/styles/${relativePath}`;
|
|
241
|
+
customAssets.css.push(outputPath);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (customAssets.css.length > 0) {
|
|
245
|
+
console.log(`📝 Copied ${customAssets.css.length} custom CSS file(s)`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Copy JavaScript files
|
|
250
|
+
if (Array.isArray(config.assets.js) && config.assets.js.length > 0) {
|
|
251
|
+
for (const jsPath of config.assets.js) {
|
|
252
|
+
const srcPath = join(config.rootDir, jsPath);
|
|
253
|
+
|
|
254
|
+
if (!existsSync(srcPath)) {
|
|
255
|
+
console.warn(`⚠️ Custom JavaScript file not found: ${jsPath}`);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Preserve directory structure in output
|
|
260
|
+
// e.g., custom/script.js -> dist/scripts/custom/script.js
|
|
261
|
+
const relativePath = jsPath.startsWith('/') ? jsPath.slice(1) : jsPath;
|
|
262
|
+
const destPath = join(outputScriptsDir, relativePath);
|
|
263
|
+
|
|
264
|
+
copyFile(srcPath, destPath);
|
|
265
|
+
|
|
266
|
+
// Store output path for template injection (relative to output root)
|
|
267
|
+
const outputPath = `/scripts/${relativePath}`;
|
|
268
|
+
customAssets.js.push(outputPath);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (customAssets.js.length > 0) {
|
|
272
|
+
console.log(`📜 Copied ${customAssets.js.length} custom JavaScript file(s)`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return customAssets;
|
|
277
|
+
}
|
|
278
|
+
|
|
203
279
|
/**
|
|
204
280
|
* Write a file with directory creation
|
|
205
281
|
*/
|
|
@@ -245,6 +321,7 @@ export default {
|
|
|
245
321
|
copyImages,
|
|
246
322
|
copyDefaultStyles,
|
|
247
323
|
copyStaticAssets,
|
|
324
|
+
copyCustomAssets,
|
|
248
325
|
writeFile,
|
|
249
326
|
cleanDir
|
|
250
327
|
};
|
package/lib/build.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'url';
|
|
|
4
4
|
import { loadConfig } from './config.js';
|
|
5
5
|
import { buildSiteData, paginate, getPaginationUrls } from './collections.js';
|
|
6
6
|
import { createTemplateEngine, renderTemplate } from './templates.js';
|
|
7
|
-
import { copyImages, copyDefaultStyles, copyStaticAssets, writeFile, ensureDir } from './assets.js';
|
|
7
|
+
import { copyImages, copyDefaultStyles, copyStaticAssets, copyCustomAssets, writeFile, ensureDir } from './assets.js';
|
|
8
8
|
import { resolveTheme } from './theme-resolver.js';
|
|
9
9
|
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -222,6 +222,10 @@ export async function build(options = {}) {
|
|
|
222
222
|
// Build site data (collections, tags, etc.)
|
|
223
223
|
const siteData = buildSiteData(config);
|
|
224
224
|
|
|
225
|
+
// Copy custom assets and add to siteData
|
|
226
|
+
const customAssets = copyCustomAssets(config);
|
|
227
|
+
siteData.customAssets = customAssets;
|
|
228
|
+
|
|
225
229
|
// Create template engine with resolved theme
|
|
226
230
|
const env = createTemplateEngine(config, resolvedTheme);
|
|
227
231
|
|
|
@@ -249,6 +253,7 @@ export async function build(options = {}) {
|
|
|
249
253
|
// Copy assets
|
|
250
254
|
copyImages(config);
|
|
251
255
|
copyDefaultStyles(config, resolvedTheme);
|
|
256
|
+
// Custom assets already copied above and added to siteData
|
|
252
257
|
copyStaticAssets(config);
|
|
253
258
|
|
|
254
259
|
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
package/lib/config.js
CHANGED
|
@@ -44,6 +44,10 @@ const defaultConfig = {
|
|
|
44
44
|
server: {
|
|
45
45
|
port: 3000,
|
|
46
46
|
showDrafts: false // Show draft posts when using dev server
|
|
47
|
+
},
|
|
48
|
+
assets: {
|
|
49
|
+
css: [], // Array of custom CSS file paths (relative to root)
|
|
50
|
+
js: [] // Array of custom JavaScript file paths (relative to root)
|
|
47
51
|
}
|
|
48
52
|
};
|
|
49
53
|
|
package/lib/content.js
CHANGED
|
@@ -351,7 +351,9 @@ export function getDateFromFilename(filename) {
|
|
|
351
351
|
const match = name.match(datePattern);
|
|
352
352
|
|
|
353
353
|
if (match) {
|
|
354
|
-
|
|
354
|
+
// Parse as local date, not UTC
|
|
355
|
+
const [year, month, day] = match[1].split('-').map(Number);
|
|
356
|
+
return new Date(year, month - 1, day);
|
|
355
357
|
}
|
|
356
358
|
|
|
357
359
|
return null;
|
|
@@ -377,7 +379,13 @@ export function parseContent(filePath) {
|
|
|
377
379
|
// Get date from front matter or filename
|
|
378
380
|
let date = frontMatter.date;
|
|
379
381
|
if (date) {
|
|
380
|
-
date
|
|
382
|
+
// If it's a date-only string (YYYY-MM-DD), parse as local date
|
|
383
|
+
if (typeof date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
384
|
+
const [year, month, day] = date.split('-').map(Number);
|
|
385
|
+
date = new Date(year, month - 1, day);
|
|
386
|
+
} else {
|
|
387
|
+
date = new Date(date);
|
|
388
|
+
}
|
|
381
389
|
} else {
|
|
382
390
|
date = getDateFromFilename(filePath) || new Date();
|
|
383
391
|
}
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
11
|
+
{% include "custom-assets-css.njk" %}
|
|
11
12
|
|
|
12
13
|
{% block head %}{% endblock %}
|
|
13
14
|
</head>
|
|
@@ -25,5 +26,6 @@
|
|
|
25
26
|
{% include "footer.njk" %}
|
|
26
27
|
</div>
|
|
27
28
|
</div>
|
|
29
|
+
{% include "custom-assets-js.njk" %}
|
|
28
30
|
</body>
|
|
29
31
|
</html>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<a href="{{ post.url }}">{{ post.title }}</a>
|
|
27
27
|
</h3>
|
|
28
28
|
|
|
29
|
-
<p class="card-excerpt">{{ post.
|
|
29
|
+
<p class="card-excerpt">{{ post.excerptHtml | safe }}</p>
|
|
30
30
|
|
|
31
31
|
<div class="card-meta">
|
|
32
32
|
<span class="card-date">{{ post.date | date('short') }}</span>
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
<a href="{{ post.url }}">{{ post.title }}</a>
|
|
24
24
|
</h2>
|
|
25
25
|
|
|
26
|
-
<p class="card-excerpt">{{ post.
|
|
26
|
+
<p class="card-excerpt">{{ post.excerptHtml | safe }}</p>
|
|
27
27
|
|
|
28
28
|
<div class="card-meta">
|
|
29
29
|
<span class="card-date">{{ post.date | date('short') }}</span>
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600&family=Source+Serif+4:opsz,wght@8..60,400;8..60,500&display=swap" rel="stylesheet">
|
|
11
|
+
{% include "custom-assets-css.njk" %}
|
|
11
12
|
|
|
12
13
|
{% block head %}{% endblock %}
|
|
13
14
|
</head>
|
|
@@ -19,5 +20,6 @@
|
|
|
19
20
|
</main>
|
|
20
21
|
|
|
21
22
|
{% include "footer.njk" %}
|
|
23
|
+
{% include "custom-assets-js.njk" %}
|
|
22
24
|
</body>
|
|
23
25
|
</html>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<h2 class="row-title">
|
|
15
15
|
<a href="{{ post.url }}">{{ post.title }}</a>
|
|
16
16
|
</h2>
|
|
17
|
-
<p class="row-excerpt">{{ post.
|
|
17
|
+
<p class="row-excerpt">{{ post.excerptHtml | safe }}</p>
|
|
18
18
|
<div class="row-meta">
|
|
19
19
|
<span class="row-author">{{ post.author or site.author }}</span>
|
|
20
20
|
<span class="meta-separator">·</span>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
{% include "theme-script.njk" %}
|
|
6
6
|
|
|
7
7
|
<link rel="stylesheet" href="{{ '/styles/main.css' | url }}">
|
|
8
|
+
{% include "custom-assets-css.njk" %}
|
|
8
9
|
|
|
9
10
|
{% block head %}{% endblock %}
|
|
10
11
|
</head>
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
</main>
|
|
17
18
|
|
|
18
19
|
{% include "footer.njk" %}
|
|
20
|
+
{% include "custom-assets-js.njk" %}
|
|
19
21
|
</body>
|
|
20
22
|
</html>
|
|
21
23
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<ul class="tag-posts">
|
|
21
21
|
{% for item in tag.items | limit(5) %}
|
|
22
22
|
<li>
|
|
23
|
-
<a href="{{ item.url }}">{{ item.title or item.
|
|
23
|
+
<a href="{{ item.url }}">{{ item.title or item.excerptHtml | safe }}</a>
|
|
24
24
|
<time datetime="{{ item.date | date('iso') }}">{{ item.date | date('short') }}</time>
|
|
25
25
|
</li>
|
|
26
26
|
{% endfor %}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
{% include "theme-script.njk" %}
|
|
6
6
|
|
|
7
7
|
<link rel="stylesheet" href="{{ '/styles/main.css' | url }}">
|
|
8
|
+
{% include "custom-assets-css.njk" %}
|
|
8
9
|
|
|
9
10
|
{% block head %}{% endblock %}
|
|
10
11
|
</head>
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
</main>
|
|
17
18
|
|
|
18
19
|
{% include "footer.njk" %}
|
|
20
|
+
{% include "custom-assets-js.njk" %}
|
|
19
21
|
</body>
|
|
20
22
|
</html>
|
|
21
23
|
|