fossbook 0.2.5 → 0.2.6
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/lib/mod/marked.js +70 -28
- package/package.json +1 -1
- package/themes/archie/assets/styles/main.css +21 -50
package/lib/mod/marked.js
CHANGED
|
@@ -9,6 +9,36 @@ function escapeAttribute(value) {
|
|
|
9
9
|
.replace(/>/g, ">");
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function getWikipediaCitation(href) {
|
|
13
|
+
let url;
|
|
14
|
+
try {
|
|
15
|
+
url = new URL(href);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const hostname = url.hostname.toLowerCase();
|
|
21
|
+
const hostnameMatch = /^([a-z-]+)\.(?:m\.)?wikipedia\.org$/.exec(hostname);
|
|
22
|
+
if (!hostnameMatch || !url.pathname.startsWith("/wiki/")) return null;
|
|
23
|
+
|
|
24
|
+
let articleTitle;
|
|
25
|
+
try {
|
|
26
|
+
articleTitle = decodeURIComponent(url.pathname.slice(6)).replace(/_/g, " ");
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (!articleTitle) return null;
|
|
31
|
+
|
|
32
|
+
const source = hostnameMatch[1] === "ko" ? "위키백과" : "Wikipedia";
|
|
33
|
+
return `${source}, ${articleTitle}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function renderWikipediaCitation(href) {
|
|
37
|
+
const citation = getWikipediaCitation(href);
|
|
38
|
+
if (!citation) return null;
|
|
39
|
+
return `<a href="${escapeAttribute(href)}">${escapeAttribute(citation)}</a>`;
|
|
40
|
+
}
|
|
41
|
+
|
|
12
42
|
function matchFencedContainer(source, name) {
|
|
13
43
|
const opening = new RegExp(`^(:{3,})${name}(?=[ \\t]|\\n)([^\\n]*)\\n`).exec(source);
|
|
14
44
|
if (!opening) return undefined;
|
|
@@ -27,15 +57,7 @@ function matchFencedContainer(source, name) {
|
|
|
27
57
|
};
|
|
28
58
|
}
|
|
29
59
|
|
|
30
|
-
const
|
|
31
|
-
["background", "--panel-background"],
|
|
32
|
-
["background-color", "--panel-background-color"],
|
|
33
|
-
["border", "--panel-border"],
|
|
34
|
-
["border-color", "--panel-border-color"],
|
|
35
|
-
["border-radius", "--panel-border-radius"],
|
|
36
|
-
["border-style", "--panel-border-style"],
|
|
37
|
-
["border-width", "--panel-border-width"],
|
|
38
|
-
["box-shadow", "--panel-box-shadow"],
|
|
60
|
+
const panelGroupStyleProperties = new Map([
|
|
39
61
|
["gap", "--panel-gap"],
|
|
40
62
|
]);
|
|
41
63
|
|
|
@@ -96,7 +118,7 @@ function parsePanelAttributes(source) {
|
|
|
96
118
|
attributePattern.lastIndex = offset;
|
|
97
119
|
const match = attributePattern.exec(source);
|
|
98
120
|
if (!match) throw new Error(`Invalid panels attribute near: ${source.slice(offset)}`);
|
|
99
|
-
if (!["columns", "label", "
|
|
121
|
+
if (!["columns", "label", "style"].includes(match[1])) {
|
|
100
122
|
throw new Error(`Unsupported panels attribute: ${match[1]}`);
|
|
101
123
|
}
|
|
102
124
|
if (Object.hasOwn(attributes, match[1])) {
|
|
@@ -111,20 +133,10 @@ function parsePanelAttributes(source) {
|
|
|
111
133
|
throw new Error("Panel columns must be an integer from 1 to 6");
|
|
112
134
|
}
|
|
113
135
|
|
|
114
|
-
if (attributes.boxed !== undefined && attributes.boxed !== "true") {
|
|
115
|
-
throw new Error('Panel boxed must be "true"');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const style = parseStyle(attributes.style || "", panelStyleProperties, "panel");
|
|
119
|
-
if (attributes.boxed !== "true" && style.some((declaration) => !declaration.startsWith("--panel-gap:"))) {
|
|
120
|
-
throw new Error('Panel card styles require boxed="true"');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
136
|
return {
|
|
124
137
|
columns,
|
|
125
138
|
label: attributes.label,
|
|
126
|
-
|
|
127
|
-
style,
|
|
139
|
+
style: parseStyle(attributes.style || "", panelGroupStyleProperties, "panel group"),
|
|
128
140
|
};
|
|
129
141
|
}
|
|
130
142
|
|
|
@@ -140,7 +152,7 @@ function parseComicPanelAttributes(source) {
|
|
|
140
152
|
attributePattern.lastIndex = offset;
|
|
141
153
|
const match = attributePattern.exec(source);
|
|
142
154
|
if (!match) throw new Error(`Invalid panel attribute near: ${source.slice(offset)}`);
|
|
143
|
-
if (!["label", "divider", "style"].includes(match[1])) {
|
|
155
|
+
if (!["label", "divider", "rounded", "style"].includes(match[1])) {
|
|
144
156
|
throw new Error(`Unsupported panel attribute: ${match[1]}`);
|
|
145
157
|
}
|
|
146
158
|
if (Object.hasOwn(attributes, match[1])) {
|
|
@@ -153,10 +165,14 @@ function parseComicPanelAttributes(source) {
|
|
|
153
165
|
if (attributes.divider !== undefined && attributes.divider !== "true") {
|
|
154
166
|
throw new Error('Panel divider must be "true"');
|
|
155
167
|
}
|
|
168
|
+
if (attributes.rounded !== undefined && attributes.rounded !== "true") {
|
|
169
|
+
throw new Error('Panel rounded must be "true"');
|
|
170
|
+
}
|
|
156
171
|
|
|
157
172
|
return {
|
|
158
173
|
label: attributes.label,
|
|
159
174
|
divider: attributes.divider === "true",
|
|
175
|
+
rounded: attributes.rounded === "true",
|
|
160
176
|
style: parseStyle(attributes.style || "", comicPanelStyleProperties, "panel"),
|
|
161
177
|
};
|
|
162
178
|
}
|
|
@@ -178,7 +194,6 @@ const panelsExtension = {
|
|
|
178
194
|
raw: container.raw,
|
|
179
195
|
columns: attributes.columns,
|
|
180
196
|
label: attributes.label,
|
|
181
|
-
boxed: attributes.boxed,
|
|
182
197
|
style: attributes.style,
|
|
183
198
|
nested: tokens.some((token) => token.type === "panel"),
|
|
184
199
|
tokens,
|
|
@@ -190,7 +205,6 @@ const panelsExtension = {
|
|
|
190
205
|
: "";
|
|
191
206
|
const className = [
|
|
192
207
|
"panel-group",
|
|
193
|
-
token.boxed ? "panel-group-boxed" : "",
|
|
194
208
|
token.nested ? "panel-group-nested" : "",
|
|
195
209
|
].filter(Boolean).join(" ");
|
|
196
210
|
const style = [`--panel-columns: ${token.columns};`, ...token.style].join(" ");
|
|
@@ -198,6 +212,26 @@ const panelsExtension = {
|
|
|
198
212
|
},
|
|
199
213
|
};
|
|
200
214
|
|
|
215
|
+
const wikipediaUrlExtension = {
|
|
216
|
+
name: "wikipediaUrl",
|
|
217
|
+
level: "inline",
|
|
218
|
+
start(source) {
|
|
219
|
+
return source.search(/https?:\/\/[a-z-]+\.(?:m\.)?wikipedia\.org\/wiki\//i);
|
|
220
|
+
},
|
|
221
|
+
tokenizer(source) {
|
|
222
|
+
const match = /^https?:\/\/[a-z-]+\.(?:m\.)?wikipedia\.org\/wiki\/[^\s<>"']+/i.exec(source);
|
|
223
|
+
if (!match) return undefined;
|
|
224
|
+
|
|
225
|
+
const raw = match[0].replace(/[.,;:!?]+$/, "");
|
|
226
|
+
const citation = getWikipediaCitation(raw);
|
|
227
|
+
if (!citation) return undefined;
|
|
228
|
+
return { type: "wikipediaUrl", raw, href: raw, citation };
|
|
229
|
+
},
|
|
230
|
+
renderer(token) {
|
|
231
|
+
return renderWikipediaCitation(token.href);
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
201
235
|
function createComicPanelExtension(name, type) {
|
|
202
236
|
return {
|
|
203
237
|
name: type,
|
|
@@ -216,6 +250,7 @@ function createComicPanelExtension(name, type) {
|
|
|
216
250
|
raw: container.raw,
|
|
217
251
|
label: attributes.label,
|
|
218
252
|
divider: attributes.divider,
|
|
253
|
+
rounded: attributes.rounded,
|
|
219
254
|
style: attributes.style,
|
|
220
255
|
tokens: this.lexer.blockTokens(container.content),
|
|
221
256
|
};
|
|
@@ -227,9 +262,11 @@ function createComicPanelExtension(name, type) {
|
|
|
227
262
|
const style = token.style.length
|
|
228
263
|
? ` style="${escapeAttribute(token.style.join(" "))}"`
|
|
229
264
|
: "";
|
|
230
|
-
const className =
|
|
231
|
-
|
|
232
|
-
|
|
265
|
+
const className = [
|
|
266
|
+
"comic-panel",
|
|
267
|
+
token.divider ? "comic-panel-divider" : "",
|
|
268
|
+
token.rounded ? "comic-panel-rounded" : "",
|
|
269
|
+
].filter(Boolean).join(" ");
|
|
233
270
|
return `<section class="${className}"${style}${label}>\n${this.parser.parse(token.tokens)}</section>\n`;
|
|
234
271
|
},
|
|
235
272
|
};
|
|
@@ -316,6 +353,11 @@ const renderer = {
|
|
|
316
353
|
`;
|
|
317
354
|
},
|
|
318
355
|
link(href, title, text) {
|
|
356
|
+
if (!title && text === href) {
|
|
357
|
+
const citation = renderWikipediaCitation(href);
|
|
358
|
+
if (citation) return citation;
|
|
359
|
+
}
|
|
360
|
+
|
|
319
361
|
let align = null;
|
|
320
362
|
if (title && title.includes("align:")) {
|
|
321
363
|
// align: left, right, center
|
|
@@ -350,7 +392,7 @@ const renderer = {
|
|
|
350
392
|
};
|
|
351
393
|
|
|
352
394
|
marked.use({
|
|
353
|
-
extensions: [panelsExtension, panelExtension],
|
|
395
|
+
extensions: [panelsExtension, panelExtension, wikipediaUrlExtension],
|
|
354
396
|
renderer,
|
|
355
397
|
hooks: {
|
|
356
398
|
postprocess(html) {
|
package/package.json
CHANGED
|
@@ -179,6 +179,10 @@
|
|
|
179
179
|
font-weight: bold;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
ol > li::marker {
|
|
183
|
+
font-family: 'Roboto Mono', monospace;
|
|
184
|
+
}
|
|
185
|
+
|
|
182
186
|
/*
|
|
183
187
|
ul.pagination {
|
|
184
188
|
display: flex;
|
|
@@ -266,60 +270,17 @@
|
|
|
266
270
|
text-align: center;
|
|
267
271
|
}
|
|
268
272
|
|
|
269
|
-
.panel-group-boxed {
|
|
270
|
-
align-items: stretch;
|
|
271
|
-
grid-auto-rows: 1fr;
|
|
272
|
-
gap: var(--panel-gap, 0.75rem);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.panel-group-boxed > .image-container {
|
|
276
|
-
height: 100%;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
.panel-group-boxed > .image-container > figure {
|
|
280
|
-
height: 100%;
|
|
281
|
-
display: flex;
|
|
282
|
-
flex-direction: column;
|
|
283
|
-
border: 1px solid #575752;
|
|
284
|
-
border-radius: var(--panel-border-radius, 0);
|
|
285
|
-
background: var(--panel-background, #fff);
|
|
286
|
-
box-shadow: var(--panel-box-shadow, none);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
.panel-group-boxed[style*="--panel-border:"] > .image-container > figure {
|
|
290
|
-
border: var(--panel-border);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.panel-group-boxed[style*="--panel-border-color:"] > .image-container > figure {
|
|
294
|
-
border-color: var(--panel-border-color);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
.panel-group-boxed[style*="--panel-border-style:"] > .image-container > figure {
|
|
298
|
-
border-style: var(--panel-border-style);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.panel-group-boxed[style*="--panel-border-width:"] > .image-container > figure {
|
|
302
|
-
border-width: var(--panel-border-width);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
.panel-group-boxed[style*="--panel-background-color:"] > .image-container > figure {
|
|
306
|
-
background-color: var(--panel-background-color);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.panel-group-boxed > .image-container > figure > figcaption {
|
|
310
|
-
flex: 1;
|
|
311
|
-
margin-top: 0;
|
|
312
|
-
padding: 0.75rem;
|
|
313
|
-
font-size: 0.9rem;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
273
|
.comic-panel {
|
|
317
274
|
margin: 2rem 0;
|
|
318
275
|
padding: 1rem;
|
|
319
|
-
border:
|
|
276
|
+
border: 1.5px solid #575752;
|
|
320
277
|
border-radius: var(--comic-panel-border-radius, 0);
|
|
321
278
|
background: var(--comic-panel-background, #fff);
|
|
322
|
-
box-shadow: var(--comic-panel-shadow,
|
|
279
|
+
box-shadow: var(--comic-panel-shadow, 2px 2px 0 rgba(70, 70, 66, 0.14));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.comic-panel-rounded {
|
|
283
|
+
--comic-panel-border-radius: 4px 7px 5px 8px / 7px 4px 8px 5px;
|
|
323
284
|
}
|
|
324
285
|
|
|
325
286
|
.comic-panel[style*="--comic-panel-border-color:"] {
|
|
@@ -378,7 +339,7 @@
|
|
|
378
339
|
margin: 1.5rem 0;
|
|
379
340
|
padding: 0.75rem;
|
|
380
341
|
border-width: 1px;
|
|
381
|
-
box-shadow:
|
|
342
|
+
box-shadow: 1px 1px 0 rgba(70, 70, 66, 0.14);
|
|
382
343
|
}
|
|
383
344
|
}
|
|
384
345
|
|
|
@@ -581,6 +542,16 @@
|
|
|
581
542
|
display: flex;
|
|
582
543
|
justify-content: space-between;
|
|
583
544
|
}
|
|
545
|
+
.post-tags ul.tags {
|
|
546
|
+
display: flex;
|
|
547
|
+
flex-wrap: wrap;
|
|
548
|
+
gap: 0.35rem 0.8rem;
|
|
549
|
+
margin: 0;
|
|
550
|
+
padding: 0;
|
|
551
|
+
}
|
|
552
|
+
.post-tags ul.tags li {
|
|
553
|
+
text-indent: 0;
|
|
554
|
+
}
|
|
584
555
|
.tags li::before{
|
|
585
556
|
content: "🏷 ";
|
|
586
557
|
}
|