hematite 0.1.13 → 0.1.16
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.
- checksums.yaml +4 -4
- data/_includes/img/chain-link.svg +29 -0
- data/_includes/recent_posts.html +24 -0
- data/_includes/settings.html +1 -0
- data/_sass/_colors.scss +40 -7
- data/_sass/_elements.scss +8 -6
- data/_sass/_layout.scss +18 -5
- data/_sass/_nav.scss +92 -1
- data/assets/html/remark_presentation_frame.html +1 -0
- data/assets/js/EscapeHelper.mjs +37 -0
- data/assets/js/Settings.mjs +12 -13
- data/assets/js/layout/calendar.mjs +2 -2
- data/assets/js/layout/post.mjs +6 -5
- data/assets/js/linkButtonGenerator.mjs +5 -2
- data/assets/js/search.mjs +24 -4
- data/assets/string_data/en.mjs +1 -0
- data/assets/string_data/es.mjs +1 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47d41c5ad077de2f9a92abb5b1b7cf4de0b161579c77de474ffaf112a859c412
|
|
4
|
+
data.tar.gz: 6115ed1ddb55c51ff476305b0ffe2b8d13df1ad66e2062b1ea35fd776e467a69
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d0089e6c81f4cceb7940a7de6bd305a554182d807cd9443264261bfd35ecb99016377e00dcf1b3523f84ea2e6330b16214b18bb87a439bca870b9fd6b4e9d7ed
|
|
7
|
+
data.tar.gz: 0ba240c05e96ffae702be804c3aef4d2f7785fa1192543836f69cf54c1ac726d58d5ca44a6578f5e3bf1eedd8a3b07be68a628048d46e12f759d11cb284fa93d
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg class="chain-link-root" width="120" height="120" version="1.1" viewBox="5 0 115 115" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<style>
|
|
4
|
+
.chain-link-group {
|
|
5
|
+
stroke: var(--primary-text-color);
|
|
6
|
+
fill: var(--primary-text-color);
|
|
7
|
+
transform: scale(1, 1);
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
|
|
10
|
+
transition: transform 0.5s ease;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
*:hover > .chain-link-root > .chain-link-group, *:focus-visible > .chain-link-root > .chain-link-group {
|
|
14
|
+
transform: scale(0.9, 0.9) rotate(3deg);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.first-link {
|
|
18
|
+
transition: transform 0.5s ease;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
*:hover > .chain-link-root .first-link, *:focus-visible > .chain-link-root .first-link {
|
|
22
|
+
transform: rotate(-1deg) translate(3px, 5px);
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
25
|
+
<g class="chain-link-group" stroke-width="1.3073px">
|
|
26
|
+
<path class="first-link" d="m33.397 50.158c-2.6598 5.036-2.2862 10.261-1.9847 14.517 0 0-15.64 22.738-7.7042 28.627 11.282 8.3732 27.844-11.316 35.784-22.274 4.6398-6.404 11.497-17.806 4.8574-22.551-4.4648-3.1911-15.534 6.396-15.534 6.396 2.4001-4.8081 3.8451-9.2997 8.8749-14.979 0 0 12.876-7.89 17.582-4.4037 10.785 7.9897 4.045 26.844-2.9517 37.755-11.67 18.198-40.276 49.141-57.96 35.093-15.977-12.692 19.037-58.18 19.037-58.18z"/>
|
|
27
|
+
<path class="second-link chain-link" d="m76.584 70.435c3.391-6.7587 5.3144-12.629 6.102-17.811 0 0 15.266-26.145 6.953-34.912-9.4283-9.9438-27.656 11.689-35.415 22.752-4.5343 6.4656-10.798 17.514-4.4871 22.614 3.5372 2.8589 13.627-3.6947 13.627-3.6947-3.7755 9.069-3.9072 9.1256-8.0298 14.333 0 0-12.197 5.8204-16.306 2.4937-10.388-8.4101-4.8557-26.982 2.3324-37.79 11.277-16.957 39.806-44.356 56.165-30.668 7.7991 6.5255 4.0194 21.892 0.36418 31.865-2.4291 6.628-21.307 30.818-21.307 30.818z"/>
|
|
28
|
+
</g>
|
|
29
|
+
</svg>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
{% assign recent_post_limit = recent_post_limit | default: site.hematite.recent_post_limit | default: 8 %}
|
|
3
|
+
|
|
4
|
+
<ul class="recent-posts recent-posts-grid">
|
|
5
|
+
{% for post in site.posts limit:recent_post_limit %}
|
|
6
|
+
<li>
|
|
7
|
+
<h2>
|
|
8
|
+
<a href="{{ post.url }}">{{ post.title }}</a>
|
|
9
|
+
<span class="post-date">{{ post.date | date_to_string }}</span>
|
|
10
|
+
</h2>
|
|
11
|
+
<p class="post-description">{{ post.content | strip_html | truncate: 200 }}</p>
|
|
12
|
+
<div class="tags">
|
|
13
|
+
{% for tag in post.tags %}
|
|
14
|
+
<a
|
|
15
|
+
href="{{ 'assets/html/all_tags.html' | relative_url }}#tag__{{ tag | uri_escape }}"
|
|
16
|
+
class="post-tag"
|
|
17
|
+
>
|
|
18
|
+
{{ tag }}
|
|
19
|
+
</a>
|
|
20
|
+
{% endfor %}
|
|
21
|
+
</div>
|
|
22
|
+
</li>
|
|
23
|
+
{% endfor %}
|
|
24
|
+
</ul>
|
data/_includes/settings.html
CHANGED
|
@@ -59,6 +59,7 @@ pageThemeSelect.innerHTML =
|
|
|
59
59
|
`
|
|
60
60
|
<option value='${Settings.THEME_AUTO}'>${stringLookup('page_theme_auto')}</option>
|
|
61
61
|
<option value='${Settings.THEME_DARK}'>${stringLookup('page_theme_dark')}</option>
|
|
62
|
+
<option value='${Settings.THEME_DARKEST}'>${stringLookup('page_theme_darkest')}</option>
|
|
62
63
|
<option value='${Settings.THEME_LIGHT}'>${stringLookup('page_theme_light')}</option>
|
|
63
64
|
`;
|
|
64
65
|
|
data/_sass/_colors.scss
CHANGED
|
@@ -29,15 +29,11 @@
|
|
|
29
29
|
--syntax-comment-fg: #338;
|
|
30
30
|
--syntax-name-fg: #331;
|
|
31
31
|
--syntax-normal-fg: black;
|
|
32
|
+
--code-background-color: #f9f5f5;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
@media screen {
|
|
35
|
-
:root:not(.darkTheme), :root.lightTheme {
|
|
36
|
-
--code-background-color: #f9f5f5;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
35
|
|
|
40
|
-
@mixin dark-theme-colors {
|
|
36
|
+
@mixin very-dark-theme-colors {
|
|
41
37
|
--primary-text-color: white;
|
|
42
38
|
--secondary-text-color: white;
|
|
43
39
|
--text-color-faint: #ccc;
|
|
@@ -47,7 +43,7 @@
|
|
|
47
43
|
--selected-item-fg-color: white;
|
|
48
44
|
--selected-item-bg-color: #530033;
|
|
49
45
|
|
|
50
|
-
--primary-background-color:
|
|
46
|
+
--primary-background-color: #000;
|
|
51
47
|
--secondary-background-color: #111;
|
|
52
48
|
--code-background-color: #222;
|
|
53
49
|
--line-color-light: #222;
|
|
@@ -70,6 +66,39 @@
|
|
|
70
66
|
--syntax-normal-fg: white;
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
@mixin dark-theme-colors {
|
|
70
|
+
--primary-text-color: white;
|
|
71
|
+
--secondary-text-color: white;
|
|
72
|
+
--text-color-faint: #ccc;
|
|
73
|
+
--link-color: #fa0;
|
|
74
|
+
--visited-link-color: #f0a;
|
|
75
|
+
|
|
76
|
+
--selected-item-fg-color: white;
|
|
77
|
+
--selected-item-bg-color: #530033;
|
|
78
|
+
|
|
79
|
+
--primary-background-color: #333;
|
|
80
|
+
--secondary-background-color: #222;
|
|
81
|
+
--code-background-color: #222;
|
|
82
|
+
--line-color-light: #555;
|
|
83
|
+
--line-color-normal: #aaa;
|
|
84
|
+
|
|
85
|
+
--color-alert-background: #300;
|
|
86
|
+
--color-alert-foreground: white;
|
|
87
|
+
|
|
88
|
+
--shadow-color-light: rgba(220, 220, 200, 0.5);
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
// Syntax highlighting
|
|
92
|
+
--syntax-keyword-fg: pink;
|
|
93
|
+
--syntax-string-fg: #cfc;
|
|
94
|
+
--syntax-number-fg: #eef;
|
|
95
|
+
--syntax-bracket-fg: #faf;
|
|
96
|
+
--syntax-operator-fg: #aff;
|
|
97
|
+
--syntax-comment-fg: #aef;
|
|
98
|
+
--syntax-name-fg: #edf;
|
|
99
|
+
--syntax-normal-fg: white;
|
|
100
|
+
}
|
|
101
|
+
|
|
73
102
|
@media screen and (prefers-color-scheme: dark) {
|
|
74
103
|
:root:not(.lightTheme) {
|
|
75
104
|
@include dark-theme-colors;
|
|
@@ -80,5 +109,9 @@
|
|
|
80
109
|
:root.darkTheme {
|
|
81
110
|
@include dark-theme-colors;
|
|
82
111
|
}
|
|
112
|
+
|
|
113
|
+
:root.veryDarkTheme {
|
|
114
|
+
@include very-dark-theme-colors;
|
|
115
|
+
}
|
|
83
116
|
}
|
|
84
117
|
|
data/_sass/_elements.scss
CHANGED
|
@@ -116,6 +116,10 @@ main pre {
|
|
|
116
116
|
padding: 4px;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
.linkToHeaderContainer > a {
|
|
120
|
+
background-color: transparent;
|
|
121
|
+
}
|
|
122
|
+
|
|
119
123
|
code {
|
|
120
124
|
box-shadow: inset -1px -1px 4px var(--shadow-color-light);
|
|
121
125
|
}
|
|
@@ -193,10 +197,6 @@ a.settings-btn {
|
|
|
193
197
|
}
|
|
194
198
|
}
|
|
195
199
|
|
|
196
|
-
:root.darkTheme main img.auto-invert {
|
|
197
|
-
@include img-invert;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
200
|
// Users can `include' this to invert images automatically in dark mode.
|
|
201
201
|
@mixin auto-invert-images {
|
|
202
202
|
@media (prefers-color-scheme: dark) {
|
|
@@ -205,7 +205,9 @@ a.settings-btn {
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
:root.darkTheme
|
|
209
|
-
|
|
208
|
+
:root.darkTheme, :root.veryDarkTheme {
|
|
209
|
+
main img:not(.no-invert) {
|
|
210
|
+
@include img-invert;
|
|
211
|
+
}
|
|
210
212
|
}
|
|
211
213
|
}
|
data/_sass/_layout.scss
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
@import "_calendar";
|
|
5
5
|
|
|
6
6
|
.main-container {
|
|
7
|
-
box-shadow:
|
|
7
|
+
box-shadow: 0px -1px 2px var(--shadow-color-light);
|
|
8
8
|
background-color: var(--primary-background-color);
|
|
9
9
|
|
|
10
10
|
max-width: $site-content-preferred-width;
|
|
@@ -139,15 +139,28 @@ nav#post_next_prev {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
.linkToHeaderContainer {
|
|
142
|
-
float: right;
|
|
143
|
-
opacity: 0.1;
|
|
144
142
|
cursor: pointer;
|
|
143
|
+
position: absolute;
|
|
144
|
+
opacity: 0.2;
|
|
145
|
+
|
|
146
|
+
a {
|
|
147
|
+
margin-left: -1em;
|
|
148
|
+
|
|
149
|
+
svg {
|
|
150
|
+
width: 1em;
|
|
151
|
+
height: 0.7em;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
145
154
|
|
|
146
155
|
transition: opacity 0.2s ease;
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
|
|
150
|
-
|
|
158
|
+
h1, h2, h3, h4, h5, h6 {
|
|
159
|
+
&:hover, &:focus-visible {
|
|
160
|
+
.linkToHeaderContainer {
|
|
161
|
+
opacity: 1;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
151
164
|
}
|
|
152
165
|
|
|
153
166
|
.spacer {
|
data/_sass/_nav.scss
CHANGED
|
@@ -124,7 +124,6 @@ nav.sidebar {
|
|
|
124
124
|
transform: scale(0, 1) translate(-30px, 0);
|
|
125
125
|
|
|
126
126
|
color: var(--primary-text-color);
|
|
127
|
-
background-color: var(--primary-background-color);
|
|
128
127
|
box-shadow: 0 0 2px var(--shadow-color-light);
|
|
129
128
|
padding: $navbar-padding;
|
|
130
129
|
|
|
@@ -138,6 +137,15 @@ nav.sidebar {
|
|
|
138
137
|
transform-origin: left;
|
|
139
138
|
transition: opacity 0.5s ease, transform 0.5s ease, width 0.5s ease;
|
|
140
139
|
|
|
140
|
+
// Work around a rendering bug in Safari — apply the background color to both
|
|
141
|
+
// the results pane and the container.
|
|
142
|
+
//
|
|
143
|
+
// Without this, Safari may display elements of pinned-pages in the same
|
|
144
|
+
// location as the search results.
|
|
145
|
+
&, .search-results {
|
|
146
|
+
background-color: var(--primary-background-color);
|
|
147
|
+
}
|
|
148
|
+
|
|
141
149
|
|
|
142
150
|
// Container with search box and button
|
|
143
151
|
> .search-container {
|
|
@@ -249,3 +257,86 @@ nav.sidebar {
|
|
|
249
257
|
.main-container * {
|
|
250
258
|
scroll-margin-top: 2.5em;
|
|
251
259
|
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
.recent-posts {
|
|
263
|
+
display: flex;
|
|
264
|
+
flex-direction: column;
|
|
265
|
+
padding-left: 0;
|
|
266
|
+
align-items: center;
|
|
267
|
+
|
|
268
|
+
flex-wrap: wrap;
|
|
269
|
+
overflow-x: auto;
|
|
270
|
+
|
|
271
|
+
li {
|
|
272
|
+
::before {
|
|
273
|
+
content: "";
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
list-style: none;
|
|
277
|
+
|
|
278
|
+
border: 1px solid var(--line-color-light);
|
|
279
|
+
border-radius: 4px;
|
|
280
|
+
padding-left: 12px;
|
|
281
|
+
padding-right: 12px;
|
|
282
|
+
margin-bottom: 4px;
|
|
283
|
+
|
|
284
|
+
h2 {
|
|
285
|
+
font-variant: small-caps;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.post-date {
|
|
289
|
+
float: right;
|
|
290
|
+
color: var(--text-color-faint);
|
|
291
|
+
|
|
292
|
+
// Ensure that there is space between the date and
|
|
293
|
+
// the post title.
|
|
294
|
+
margin-left: 30px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.post-description {
|
|
298
|
+
color: var(--text-color-faint);
|
|
299
|
+
font-style: italic;
|
|
300
|
+
font-weight: 200;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.tags {
|
|
304
|
+
opacity: 0.7;
|
|
305
|
+
font-size: 0.8em;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Scrollable grid layout for the recent posts widget.
|
|
311
|
+
.recent-posts-grid {
|
|
312
|
+
max-height: 500px;
|
|
313
|
+
|
|
314
|
+
li {
|
|
315
|
+
max-width: Min(50vw, 500px);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
@media screen and (max-width: 500px) {
|
|
319
|
+
max-height: 100vh;
|
|
320
|
+
|
|
321
|
+
li {
|
|
322
|
+
max-width: unset;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@media print {
|
|
328
|
+
.recent-posts {
|
|
329
|
+
display: none;
|
|
330
|
+
|
|
331
|
+
// Should we decide to show the recent posts,
|
|
332
|
+
// ensure that they're in a list format.
|
|
333
|
+
max-height: unset;
|
|
334
|
+
max-width: unset;
|
|
335
|
+
overflow-x: hidden;
|
|
336
|
+
|
|
337
|
+
li {
|
|
338
|
+
max-width: unset;
|
|
339
|
+
border: none;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
import { assertEq } from "./assertions.mjs";
|
|
3
|
+
|
|
4
|
+
let htmlReplacements = [
|
|
5
|
+
[ /[&]/g, '&' ],
|
|
6
|
+
[ /[<]/g, '<' ],
|
|
7
|
+
[ /[>]/g, '>' ],
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
var EscapeHelper = {
|
|
11
|
+
escapeHTML(text) {
|
|
12
|
+
for (const item of htmlReplacements) {
|
|
13
|
+
text = text.replace(item[0], item[1]);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return text;
|
|
17
|
+
},
|
|
18
|
+
// Escape for usage within a regex expression
|
|
19
|
+
escapeRegex(text) {
|
|
20
|
+
return text.replace(/([\*\(\).\[\]\{\}\^\$\-\=\;\:\'\"\\])/g, '\\$1'); //'
|
|
21
|
+
},
|
|
22
|
+
// Escape text for usage within a replacement pattern
|
|
23
|
+
// E.g. "foobar".replaceAll("foo", text);
|
|
24
|
+
escapeReplacePattern(text) {
|
|
25
|
+
return text.replace(/\$/g, '$$$$');
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
assertEq("Test escape <", EscapeHelper.escapeHTML('<'), '<');
|
|
30
|
+
assertEq("Test escape multiple <", EscapeHelper.escapeHTML('<a></a>'), '<a></a>');
|
|
31
|
+
assertEq("Test escape >", EscapeHelper.escapeHTML('>'), '>');
|
|
32
|
+
assertEq("Test escape identity", EscapeHelper.escapeHTML('Hello, world.'), 'Hello, world.');
|
|
33
|
+
assertEq("Test regex escape simple", EscapeHelper.escapeRegex(".*"), "\\.\\*");
|
|
34
|
+
assertEq("Test regex more complicated escape", EscapeHelper.escapeRegex("This, is a test... :)"), "This, is a test\\.\\.\\. \\:\\)");
|
|
35
|
+
assertEq("Test replace pattern escape", EscapeHelper.escapeReplacePattern("0$ and 24 cents"), "0$$ and 24 cents");
|
|
36
|
+
|
|
37
|
+
export default EscapeHelper;
|
data/assets/js/Settings.mjs
CHANGED
|
@@ -8,6 +8,7 @@ const THEME_TRANSITION_TIME = 500; // ms
|
|
|
8
8
|
class Settings {
|
|
9
9
|
THEME_AUTO = 'auto';
|
|
10
10
|
THEME_DARK = 'dark';
|
|
11
|
+
THEME_DARKEST = 'darkest';
|
|
11
12
|
THEME_LIGHT = 'light';
|
|
12
13
|
|
|
13
14
|
FONT_DEFAULT = 'default';
|
|
@@ -94,20 +95,13 @@ class Settings {
|
|
|
94
95
|
return this.getFontSize() != this.FONT_SIZE_DEFAULT;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
forcingDarkTheme_() {
|
|
98
|
-
return this.getTheme() == this.THEME_DARK;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
forcingLightTheme_() {
|
|
102
|
-
return this.getTheme() == this.THEME_LIGHT;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
98
|
async applySettings() {
|
|
106
99
|
document.documentElement.classList.add("changingTheme");
|
|
107
100
|
|
|
108
101
|
// Clean up previous changes. We might be re-applying styles.
|
|
109
102
|
document.documentElement.classList.remove("lightTheme");
|
|
110
103
|
document.documentElement.classList.remove("darkTheme");
|
|
104
|
+
document.documentElement.classList.remove("veryDarkTheme");
|
|
111
105
|
|
|
112
106
|
if (!this.style_) {
|
|
113
107
|
this.style_ = document.createElement("style");
|
|
@@ -147,11 +141,16 @@ class Settings {
|
|
|
147
141
|
document.documentElement.appendChild(this.style_);
|
|
148
142
|
|
|
149
143
|
// Theme
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
switch (this.getTheme()) {
|
|
145
|
+
case this.THEME_DARK:
|
|
146
|
+
document.documentElement.classList.add("darkTheme");
|
|
147
|
+
break;
|
|
148
|
+
case this.THEME_DARKEST:
|
|
149
|
+
document.documentElement.classList.add("veryDarkTheme");
|
|
150
|
+
break;
|
|
151
|
+
case this.THEME_LIGHT:
|
|
152
|
+
document.documentElement.classList.add("lightTheme");
|
|
153
|
+
break;
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
if (this.getHeaderMinimized()) {
|
|
@@ -43,7 +43,7 @@ function getCalendarData(elem, formatElemLabels, dateHeaderTag) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
catch (e) {
|
|
46
|
-
|
|
46
|
+
errored = true;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (errored) {
|
|
@@ -277,7 +277,7 @@ class Calendar {
|
|
|
277
277
|
return this.data_[i];
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
return null;
|
|
280
|
+
return this.data_[this.data_.length - 1] ?? null;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
/// Get an item in [data_] from [date], if [searchDate]
|
data/assets/js/layout/post.mjs
CHANGED
|
@@ -37,6 +37,12 @@ function createTagLinks(page) {
|
|
|
37
37
|
let label = document.querySelector("#post_tags > #tag_header_lbl");
|
|
38
38
|
label.innerText = stringLookup(`tags`);
|
|
39
39
|
|
|
40
|
+
// Don't show the tag container if there aren't any tags
|
|
41
|
+
if (!page.tags || page.tags.length == 0) {
|
|
42
|
+
container.style.display = "none";
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
for (const tag of page.tags) {
|
|
41
47
|
let tagElem = document.createElement("a");
|
|
42
48
|
tagElem.style.display = "inline-block";
|
|
@@ -47,11 +53,6 @@ function createTagLinks(page) {
|
|
|
47
53
|
|
|
48
54
|
container.appendChild(tagElem);
|
|
49
55
|
}
|
|
50
|
-
|
|
51
|
-
// Don't show the tag container if there aren't any tags
|
|
52
|
-
if (page.tags.length == 0) {
|
|
53
|
-
container.style.display = "none";
|
|
54
|
-
}
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
function fillDate(page) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
---
|
|
1
3
|
|
|
2
4
|
import { PageAlert } from "./PageAlert.mjs";
|
|
3
5
|
import { stringLookup as _L } from './strings.mjs';
|
|
4
6
|
|
|
5
|
-
const
|
|
7
|
+
const INTERIOR_LINK_CONTENT_HTML = `{% include img/chain-link.svg %}`;
|
|
6
8
|
const INTERIOR_LINK_CONTAINER_CLSS = "linkToHeaderContainer";
|
|
7
9
|
|
|
8
10
|
/// Creates 🔗 buttons for every header with an ID.
|
|
@@ -25,9 +27,10 @@ function createLinkButton_(header) {
|
|
|
25
27
|
let headerText = header.innerText;
|
|
26
28
|
|
|
27
29
|
container.classList.add(INTERIOR_LINK_CONTAINER_CLSS);
|
|
28
|
-
link.innerText = INTERIOR_LINK_TEXT;
|
|
29
30
|
link.title = _L("copy_link_to_header", headerText);
|
|
30
31
|
link.href = `#${header.getAttribute('id')}`;
|
|
32
|
+
link.innerHTML = INTERIOR_LINK_CONTENT_HTML;
|
|
33
|
+
|
|
31
34
|
link.onclick = () => {
|
|
32
35
|
navigator.clipboard.writeText(link.href);
|
|
33
36
|
PageAlert.builder()
|
data/assets/js/search.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { expandContainingDropdowns } from "./dropdownExpander.mjs";
|
|
|
7
7
|
import AnimationUtil from "./AnimationUtil.mjs";
|
|
8
8
|
import AsyncUtil from "./AsyncUtil.mjs";
|
|
9
9
|
import UrlHelper from "./UrlHelper.mjs";
|
|
10
|
+
import EscapeHelper from "./EscapeHelper.mjs";
|
|
10
11
|
|
|
11
12
|
const PAGE_DATA_URL = `{{ "/assets/search_data.json" | relative_url }}`;
|
|
12
13
|
const MATCHING_TITLE_PRIORITY_INCREMENT = 15;
|
|
@@ -177,6 +178,7 @@ class Searcher {
|
|
|
177
178
|
results.push({
|
|
178
179
|
index,
|
|
179
180
|
context,
|
|
181
|
+
matchIndex: matchLoc,
|
|
180
182
|
pageData,
|
|
181
183
|
});
|
|
182
184
|
|
|
@@ -305,17 +307,35 @@ function handleSearch(searcher) {
|
|
|
305
307
|
|
|
306
308
|
searchResults.replaceChildren(descriptionElem);
|
|
307
309
|
|
|
310
|
+
// Adds HTML to bold/italicize all results in [context].
|
|
311
|
+
// [context] is HTML-escaped before adding to the result.
|
|
312
|
+
const boldResults = (context) => {
|
|
313
|
+
let result = "";
|
|
314
|
+
let queryRegex = new RegExp(`(${EscapeHelper.escapeRegex(query)})`, `ig`);
|
|
315
|
+
let contextHTML = "";
|
|
316
|
+
let lastIdx = 0;
|
|
317
|
+
for (const match of context.matchAll(queryRegex)) {
|
|
318
|
+
result += EscapeHelper.escapeHTML(context.substring(lastIdx, match.index));
|
|
319
|
+
result += "<b><i>" + EscapeHelper.escapeHTML(match[0]) + "</i></b>";
|
|
320
|
+
lastIdx = match.index + match[0].length;
|
|
321
|
+
}
|
|
322
|
+
result += EscapeHelper.escapeHTML(context.substring(lastIdx));
|
|
323
|
+
|
|
324
|
+
return result;
|
|
325
|
+
};
|
|
326
|
+
|
|
308
327
|
for (const result of results) {
|
|
309
328
|
let link = document.createElement("a");
|
|
310
|
-
let
|
|
311
|
-
|
|
329
|
+
let contextElem = document.createElement("div");
|
|
330
|
+
contextElem.classList.add('context');
|
|
312
331
|
|
|
313
332
|
link.innerText = result.pageData.title ?? stringLookup(`untitled`);
|
|
314
333
|
link.href =
|
|
315
334
|
result.pageData.url + `?query=${escape(query)},index=${result.index}`;
|
|
316
|
-
context.innerText = result.context;
|
|
317
335
|
|
|
318
|
-
|
|
336
|
+
contextElem.innerHTML = boldResults(result.context);
|
|
337
|
+
|
|
338
|
+
link.appendChild(contextElem);
|
|
319
339
|
searchResults.appendChild(link);
|
|
320
340
|
}
|
|
321
341
|
|
data/assets/string_data/en.mjs
CHANGED
data/assets/string_data/es.mjs
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hematite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Henry Heino
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-05
|
|
11
|
+
date: 2022-09-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|
|
@@ -36,6 +36,7 @@ files:
|
|
|
36
36
|
- _config.yml
|
|
37
37
|
- _includes/extern_library_imports.html
|
|
38
38
|
- _includes/footer.html
|
|
39
|
+
- _includes/img/chain-link.svg
|
|
39
40
|
- _includes/img/hamburger_menu.svg
|
|
40
41
|
- _includes/img/loading_icon.svg
|
|
41
42
|
- _includes/img/search_icon.svg
|
|
@@ -46,6 +47,7 @@ files:
|
|
|
46
47
|
- _includes/nav/pages_list.html
|
|
47
48
|
- _includes/nav/pinned_page.html
|
|
48
49
|
- _includes/nav/sidebar.html
|
|
50
|
+
- _includes/recent_posts.html
|
|
49
51
|
- _includes/scss/_fonts.scss
|
|
50
52
|
- _includes/settings.html
|
|
51
53
|
- _layouts/calendar.html
|
|
@@ -75,6 +77,7 @@ files:
|
|
|
75
77
|
- assets/js/AnimationUtil.mjs
|
|
76
78
|
- assets/js/AsyncUtil.mjs
|
|
77
79
|
- assets/js/DateUtil.mjs
|
|
80
|
+
- assets/js/EscapeHelper.mjs
|
|
78
81
|
- assets/js/PageAlert.mjs
|
|
79
82
|
- assets/js/Settings.mjs
|
|
80
83
|
- assets/js/UrlHelper.mjs
|