@rettangoli/sites 1.0.0-rc1 → 1.0.0-rc3
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/README.md +4 -0
- package/package.json +1 -1
- package/src/builtinTemplateFunctions.js +48 -0
- package/src/cli/watch.js +25 -17
- package/templates/default/README.md +4 -0
package/README.md
CHANGED
|
@@ -115,10 +115,14 @@ Available in YAML templates/pages without extra setup:
|
|
|
115
115
|
- `jsonStringify(value, space = 0)`
|
|
116
116
|
- `formatDate(value, format = "YYYYMMDDHHmmss", useUtc = true)`
|
|
117
117
|
- `now(format = "YYYYMMDDHHmmss", useUtc = true)`
|
|
118
|
+
- `sort(list, key, order = "asc")`
|
|
119
|
+
- `md(content)`
|
|
118
120
|
- `toQueryString(object)`
|
|
119
121
|
|
|
120
122
|
`formatDate` tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
|
|
121
123
|
`decodeURI`/`decodeURIComponent` return the original input when decoding fails.
|
|
124
|
+
`sort` supports `order` as `asc` or `desc` and returns a new array.
|
|
125
|
+
`md` returns raw rendered HTML from Markdown for template insertion.
|
|
122
126
|
|
|
123
127
|
## Screenshots
|
|
124
128
|
|
package/package.json
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import MarkdownIt from 'markdown-it';
|
|
2
|
+
|
|
3
|
+
const markdownRenderer = new MarkdownIt();
|
|
4
|
+
|
|
1
5
|
function toDate(value) {
|
|
2
6
|
if (value instanceof Date) {
|
|
3
7
|
return value;
|
|
@@ -71,6 +75,48 @@ function safeDecode(value, decoder) {
|
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
|
|
78
|
+
function sortImpl(value, key, order = 'asc') {
|
|
79
|
+
if (!Array.isArray(value)) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const normalizedOrder = String(order ?? 'asc').toLowerCase() === 'desc' ? 'desc' : 'asc';
|
|
83
|
+
const factor = normalizedOrder === 'asc' ? 1 : -1;
|
|
84
|
+
return [...value].sort((left, right) => {
|
|
85
|
+
const leftRaw = key == null ? left : left?.[key];
|
|
86
|
+
const rightRaw = key == null ? right : right?.[key];
|
|
87
|
+
|
|
88
|
+
if (leftRaw == null && rightRaw == null) return 0;
|
|
89
|
+
if (leftRaw == null) return 1;
|
|
90
|
+
if (rightRaw == null) return -1;
|
|
91
|
+
|
|
92
|
+
const leftDate = Date.parse(String(leftRaw));
|
|
93
|
+
const rightDate = Date.parse(String(rightRaw));
|
|
94
|
+
const canCompareAsDate = !Number.isNaN(leftDate) && !Number.isNaN(rightDate);
|
|
95
|
+
|
|
96
|
+
if (canCompareAsDate) {
|
|
97
|
+
if (leftDate === rightDate) return 0;
|
|
98
|
+
return leftDate > rightDate ? factor : -factor;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (typeof leftRaw === 'number' && typeof rightRaw === 'number') {
|
|
102
|
+
if (leftRaw === rightRaw) return 0;
|
|
103
|
+
return leftRaw > rightRaw ? factor : -factor;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const leftText = String(leftRaw);
|
|
107
|
+
const rightText = String(rightRaw);
|
|
108
|
+
const result = leftText.localeCompare(rightText);
|
|
109
|
+
if (result === 0) return 0;
|
|
110
|
+
return result > 0 ? factor : -factor;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function mdImpl(content) {
|
|
115
|
+
return {
|
|
116
|
+
__html: markdownRenderer.render(String(content ?? '')),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
74
120
|
export const builtinTemplateFunctions = {
|
|
75
121
|
encodeURI: (value) => encodeURI(String(value ?? '')),
|
|
76
122
|
encodeURIComponent: (value) => encodeURIComponent(String(value ?? '')),
|
|
@@ -79,6 +125,8 @@ export const builtinTemplateFunctions = {
|
|
|
79
125
|
jsonStringify,
|
|
80
126
|
formatDate: formatDateImpl,
|
|
81
127
|
now: (format = 'YYYYMMDDHHmmss', useUtc = true) => formatDateImpl(new Date(), format, useUtc),
|
|
128
|
+
sort: sortImpl,
|
|
129
|
+
md: mdImpl,
|
|
82
130
|
toQueryString,
|
|
83
131
|
};
|
|
84
132
|
|
package/src/cli/watch.js
CHANGED
|
@@ -54,6 +54,25 @@ export function createClientScript(reloadMode = 'body') {
|
|
|
54
54
|
`;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export function getContentType(ext) {
|
|
58
|
+
const types = {
|
|
59
|
+
'.html': 'text/html; charset=utf-8',
|
|
60
|
+
'.css': 'text/css; charset=utf-8',
|
|
61
|
+
'.js': 'application/javascript; charset=utf-8',
|
|
62
|
+
'.json': 'application/json; charset=utf-8',
|
|
63
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
64
|
+
'.md': 'text/plain; charset=utf-8',
|
|
65
|
+
'.png': 'image/png',
|
|
66
|
+
'.jpg': 'image/jpeg',
|
|
67
|
+
'.jpeg': 'image/jpeg',
|
|
68
|
+
'.gif': 'image/gif',
|
|
69
|
+
'.svg': 'image/svg+xml',
|
|
70
|
+
'.ico': 'image/x-icon',
|
|
71
|
+
'.webp': 'image/webp'
|
|
72
|
+
};
|
|
73
|
+
return types[ext] || 'application/octet-stream';
|
|
74
|
+
}
|
|
75
|
+
|
|
57
76
|
function createLogger(quiet = false) {
|
|
58
77
|
return {
|
|
59
78
|
log: (...args) => {
|
|
@@ -163,7 +182,7 @@ class DevServer {
|
|
|
163
182
|
|
|
164
183
|
serveFile(filePath, res) {
|
|
165
184
|
const ext = path.extname(filePath);
|
|
166
|
-
const contentType =
|
|
185
|
+
const contentType = getContentType(ext);
|
|
167
186
|
|
|
168
187
|
try {
|
|
169
188
|
let content = fs.readFileSync(filePath);
|
|
@@ -181,7 +200,11 @@ class DevServer {
|
|
|
181
200
|
}
|
|
182
201
|
}
|
|
183
202
|
|
|
184
|
-
|
|
203
|
+
const headers = { 'Content-Type': contentType };
|
|
204
|
+
if (ext === '.md' || ext === '.txt') {
|
|
205
|
+
headers['Content-Disposition'] = 'inline';
|
|
206
|
+
}
|
|
207
|
+
res.writeHead(200, headers);
|
|
185
208
|
res.end(content);
|
|
186
209
|
} catch (err) {
|
|
187
210
|
this.logger.error('Error serving file:', err);
|
|
@@ -190,21 +213,6 @@ class DevServer {
|
|
|
190
213
|
}
|
|
191
214
|
}
|
|
192
215
|
|
|
193
|
-
getContentType(ext) {
|
|
194
|
-
const types = {
|
|
195
|
-
'.html': 'text/html',
|
|
196
|
-
'.css': 'text/css',
|
|
197
|
-
'.js': 'application/javascript',
|
|
198
|
-
'.json': 'application/json',
|
|
199
|
-
'.png': 'image/png',
|
|
200
|
-
'.jpg': 'image/jpeg',
|
|
201
|
-
'.gif': 'image/gif',
|
|
202
|
-
'.svg': 'image/svg+xml',
|
|
203
|
-
'.ico': 'image/x-icon'
|
|
204
|
-
};
|
|
205
|
-
return types[ext] || 'application/octet-stream';
|
|
206
|
-
}
|
|
207
|
-
|
|
208
216
|
reloadAll() {
|
|
209
217
|
// Send a simple reload command to all clients
|
|
210
218
|
const message = JSON.stringify({
|
|
@@ -227,10 +227,14 @@ Use these directly in `${...}` expressions:
|
|
|
227
227
|
- `jsonStringify(value, space = 0)`
|
|
228
228
|
- `formatDate(value, format = "YYYYMMDDHHmmss", useUtc = true)`
|
|
229
229
|
- `now(format = "YYYYMMDDHHmmss", useUtc = true)`
|
|
230
|
+
- `sort(list, key, order = "asc")`
|
|
231
|
+
- `md(content)`
|
|
230
232
|
- `toQueryString(object)`
|
|
231
233
|
|
|
232
234
|
Date format tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
|
|
233
235
|
`decodeURI`/`decodeURIComponent` return the original input when decoding fails.
|
|
236
|
+
`sort` supports `order` as `asc` or `desc` and returns a new array.
|
|
237
|
+
`md` returns raw rendered HTML from Markdown for template insertion.
|
|
234
238
|
|
|
235
239
|
## Static Files
|
|
236
240
|
|