hematite 0.0.12 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ba3735a0bf64aa9c895fc9622e0370b0827c80386469ccb4c5172058f91db97
4
- data.tar.gz: e6f824c10b0febde44d427ee0528681f756cc59bff67a3362e256d77d5be3650
3
+ metadata.gz: 57c0b3ae9bdec4a2e37d649a52dfbacb84a8c09b258d2a5bb676571c5fed060d
4
+ data.tar.gz: '09bc9aa4956973f5cbb3dfa1e4889b9adfe70928eb5f2f25518b09b863a4e8ed'
5
5
  SHA512:
6
- metadata.gz: 958067abc2e83cbecc509dc7c31c2eb711c2116ea201a27c28f6a89bc0f0a6658d34532433596b989178ab070d686c2a5de0d26781ff6b92d73fdc6416f9608f
7
- data.tar.gz: e01cb8c28899e24135e832ef89543c9266e66db13d9a53f40327d6c32b6d8ed815d5da7247a63fd88ca94dc762180ab752fb8494c2d9e31d3ae2ed13fdda6297
6
+ metadata.gz: 86065a34d00cc7d8844bdd02883dc7c8dd25c4c6436a1d4b28747d0140d4409d0ac7e7a910d8fe4f54ba546c303208cb347d598141a6e66b1d0c5607e282f249
7
+ data.tar.gz: 2b218f88fec888c6029650fdd29b0809729cd321905e25e9151e26173347e7488813eebcc79d32c7ced657d8a4ce7a0e2acb4b9386e9d683607b6622e6911784
@@ -0,0 +1,11 @@
1
+ <!--
2
+ Include all external libraries (that are bundled with Hematite) requested by the
3
+ page
4
+ -->
5
+
6
+ {% include mermaid_includes.html %}
7
+ {% include katex_includes.html %}
8
+
9
+ <!-- Page/site-specific imports and configuration -->
10
+ {{ site.additional_import_html | default: "" }}
11
+ {{ page.additional_import_html | default: "" }}
@@ -4,7 +4,7 @@
4
4
  KaTeX can be enabled with page.katex.
5
5
  -->
6
6
 
7
- {% if page.katex %}
7
+ {% if page.katex || site.mermaid %}
8
8
 
9
9
  <!-- See the releases tab on https://github.com/KaTeX/KaTeX -->
10
10
  <link
@@ -0,0 +1,24 @@
1
+
2
+ <!--
3
+ Include mermaid-js scripts.
4
+ -->
5
+ {% if page.mermaid || site.mermaid %}
6
+ <script>
7
+ var MERMAID_CONFIG = window.MERMAID_CONFIG ?? {{ site.mermaid_config | jsonify }} ?? { };
8
+
9
+ // Load defaults
10
+ MERMAID_CONFIG.startOnLoad ??= true;
11
+ MERMAID_CONFIG.htmlLabels ??= true;
12
+ </script>
13
+ <script
14
+ defer
15
+ src="{{ "assets/plugin/mermaid/mermaid.js" | relative_url }}"
16
+ {% comment %}
17
+ Here, we're also calling "mermaid.init()" because of the defer attribute — it's
18
+ possible that the window has already loaded (and thus startOnLoad may have no effect).
19
+ {% endcomment %}
20
+ onload="mermaid.initialize(MERMAID_CONFIG); mermaid.init();" >
21
+ </script>
22
+
23
+ {% endif %}
24
+
@@ -10,10 +10,14 @@ title: Untitled
10
10
  {% assign content_start = page.content | slice: 0, 100 %}
11
11
  <meta name="description" content={{ page.description | default: content_start | strip_html | jsonify }}/>
12
12
  <link rel="stylesheet" href="{{ "assets/style.css" | relative_url }}"/>
13
- <link rel="icon" href="{{ page.favicon_path | default: site.favicon_path | default: "assets/img/favicon.svg" | absolute_url }}"/>
13
+ {% if page.favicon_url_absolute or site.favicon_url_absolute %}
14
+ <link rel="icon" href="{{ page.favicon_url_absolute | default: site.favicon_url_absolute }}"/>
15
+ {% else %}
16
+ <link rel="icon" href="{{ page.favicon_url | default: site.favicon_url | default: "assets/img/favicon.svg" | absolute_url }}"/>
17
+ {% endif %}
14
18
  <script type="module" src="{{ "assets/js/main.mjs" | relative_url }}"></script>
15
19
 
16
- {% include katex_includes.html %}
20
+ {% include extern_library_imports.html %}
17
21
 
18
22
  <title>{{ page.title }} — {{ site.title }}</title>
19
23
  </head>
@@ -0,0 +1,88 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ <!-- Defines a https://remarkjs.com/ slideshow -->
6
+ <!-- Configure remark with
7
+ page.remark_presentation_config, site.remark_presentation_config,
8
+ page.remark_presentation_config_html
9
+ -->
10
+
11
+ {% assign frame_resource_url = 'assets/html/remark_presentation_frame.html.resource' | relative_url %}
12
+
13
+ <main class="slideshow-mode">
14
+ <iframe
15
+ id="presentation_frame"
16
+ onload="window.presentationFrameLoaded = true;"></iframe>
17
+ </main>
18
+
19
+ <script defer type="module">
20
+ import slideshow from "{{ 'assets/js/layout/remark_slideshow.mjs' | relative_url }}";
21
+
22
+ let presentationFrame = document.querySelector("#presentation_frame");
23
+ presentationFrame.src = {{ frame_resource_url | jsonify }};
24
+ window.presentationFrameLoaded = false;
25
+
26
+ let config =
27
+ {{ page.remark_presentation_config | default: site.remark_presentation_config | jsonify }};
28
+ config ??= {};
29
+
30
+ config.source = {{ page.content | jsonify }};
31
+
32
+ // Library imports intended for this page: Forward to the frame.
33
+ let libraryImports = unescape(`
34
+ {% capture library_imports %}
35
+ {% include extern_library_imports.html %}
36
+ {% endcapture %}
37
+ {{ library_imports | url_encode | replace: "+", " " }}
38
+ `);
39
+
40
+ // To be called after the presentation iframe loads.
41
+ window.initSlides = () => {
42
+ let presentationDoc = presentationFrame.contentDocument;
43
+ let presentationWin = presentationFrame.contentWindow;
44
+
45
+ // Ensure that onload doesn't get called again if the frame reloads.
46
+ presentationFrame.onload = null;
47
+
48
+ // Re-create the document, add the library imports to it.
49
+ let slideshowHtml = presentationDoc.documentElement.outerHTML;
50
+
51
+ presentationDoc.open();
52
+ presentationDoc.write("<!DOCTYPE html>");
53
+ presentationDoc.write(slideshowHtml);
54
+ presentationDoc.write(libraryImports);
55
+
56
+ // Any additional configuration scripts/html specific to remark
57
+ presentationDoc.write(unescape(
58
+ {{ page.remark_presentation_config_html | default: "" | url_encode | replace: "+", " " | jsonify }}
59
+ ));
60
+
61
+ presentationDoc.write(`
62
+ <${"script"}>
63
+ if (window.MERMAID_CONFIG) {
64
+ window.MERMAID_CONFIG.useMaxWidth = true;
65
+ window.MERMAID_CONFIG.cloneCssStyles = false;
66
+ window.MERMAID_CONFIG.flowchart = { useMaxWidth: true };
67
+ }
68
+ </${"script"}>
69
+ `);
70
+ presentationDoc.close();
71
+ (async () => {
72
+ await slideshow.start(presentationFrame.contentWindow, config);
73
+
74
+ // Ensure that mermaid has already been run!
75
+ if (presentationWin.mermaid) {
76
+ presentationWin.mermaid.init();
77
+ console.log("Ran mermaid!");
78
+ }
79
+ })();
80
+ };
81
+
82
+ if (window.presentationFrameLoaded) {
83
+ initSlides();
84
+ }
85
+ else {
86
+ presentationFrame.onload = initSlides;
87
+ }
88
+ </script>
data/_sass/_elements.scss CHANGED
@@ -117,14 +117,31 @@ input::placeholder {
117
117
  }
118
118
  }
119
119
 
120
+ table {
121
+ border-collapse: collapse;
122
+ }
123
+
120
124
  table td {
121
125
  border: 1px solid var(--line-color-light);
126
+ padding: 3px;
127
+ }
128
+
129
+ table th {
130
+ padding: 4px;
131
+ font-weight: bold;
122
132
  }
123
133
 
124
134
  fieldset {
125
135
  border-color: var(--line-color-normal);
126
136
  margin-bottom: 30px;
127
137
  }
138
+
139
+ blockquote {
140
+ border-left: 1px solid var(--line-color-light);
141
+ margin-left: 10px;
142
+ padding-left: 20px;
143
+ color: var(--text-color-faint);
144
+ }
128
145
  }
129
146
 
130
147
  // Markdown parsers may put `code` elements inside of `pre`
data/_sass/_hljs.scss ADDED
@@ -0,0 +1,36 @@
1
+
2
+ // Created while referencing rouge-github.scss as published
3
+ // at https://github.com/pages-themes/cayman/blob/master/_sass/rouge-github.scss
4
+
5
+ .hljs {
6
+ color: var(--syntax-normal-fg);
7
+ display: block;
8
+ white-space: pre-wrap;
9
+
10
+ // Keywords and literals
11
+ .hljs-keyword, .hljs-literal {
12
+ color: var(--syntax-keyword-fg);
13
+ }
14
+
15
+ .hljs-literal {
16
+ font-weight: bold;
17
+ color: var(--syntax-name-fg);
18
+ }
19
+
20
+ // Strings
21
+ .hljs-string {
22
+ color: var(--syntax-string-fg);
23
+ }
24
+
25
+ // Numbers
26
+ .hljs-number {
27
+ color: var(--syntax-number-fg);
28
+ }
29
+
30
+
31
+ // Comments
32
+ .hljs-comment {
33
+ color: var(--syntax-comment-fg);
34
+ font-style: italic;
35
+ }
36
+ }
data/_sass/_layout.scss CHANGED
@@ -154,6 +154,21 @@ nav#post_next_prev {
154
154
  flex-grow: 1;
155
155
  }
156
156
 
157
+ main.slideshow-mode {
158
+ position: absolute;
159
+ display: flex;
160
+
161
+ left: 0;
162
+ right: 0;
163
+ top: var(--header-effective-height);
164
+ bottom: 0;
165
+
166
+ iframe {
167
+ flex-grow: 1;
168
+ border: none;
169
+ }
170
+ }
171
+
157
172
  // On mobile devices,
158
173
  @media screen and (max-width: $site-content-preferred-width) {
159
174
  .main-container {
data/_sass/_nav.scss CHANGED
@@ -41,6 +41,14 @@ body > header {
41
41
  }
42
42
  }
43
43
 
44
+ :root {
45
+ --header-effective-height: var(--header-height);
46
+ }
47
+
48
+ :root.minimizedNavHeader {
49
+ --header-effective-height: 0px;
50
+ }
51
+
44
52
  :root.minimizedNavHeader body > header {
45
53
  > *:not(#toggle_sidebar_btn) {
46
54
  opacity: 0;
@@ -48,6 +56,11 @@ body > header {
48
56
  transition: opacity 0.5s ease;
49
57
  }
50
58
 
59
+ #toggle_sidebar_btn {
60
+ padding-left: 4px;
61
+ width: var(--header-height);
62
+ }
63
+
51
64
  word-wrap: break-word;
52
65
  width: var(--header-height);
53
66
  padding: 0;
data/_sass/hematite.scss CHANGED
@@ -12,3 +12,4 @@
12
12
  @import "_layout";
13
13
  @import "_elements";
14
14
  @import "_rogue";
15
+ @import "_hljs";
@@ -0,0 +1,69 @@
1
+ ---
2
+ ---
3
+ <!-- Using a .html.resource file to prevent Jekyll from changing the extension -->
4
+
5
+ <!DOCTYPE html>
6
+ <html class="lightTheme" lang="{{ page.lang | default: site.lang | default: "en-US" }}">
7
+ <head>
8
+ <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
9
+ <meta charset="utf-8"/>
10
+ <!-- Content of remark presentation iframe. Based on https://github.com/gnab/remark/wiki#getting-started -->
11
+ <style>
12
+ /* Stylesheet mostly taken from https://github.com/gnab/remark/wiki#getting-started */
13
+ @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
14
+ @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
15
+ @import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
16
+
17
+ body { font-family: 'Droid Serif'; }
18
+ h1, h2, h3 {
19
+ font-family: 'Yanone Kaffeesatz';
20
+ font-weight: normal;
21
+ }
22
+
23
+ .remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
24
+
25
+ /* Show hidden slides to allow preprocessors (e.g. mermaid) to
26
+ properly account for container size.
27
+ */
28
+ @media screen {
29
+ .remark-slide-container:not(.remark-visible) {
30
+ display: block;
31
+ box-shadow: none;
32
+ z-index: -999;
33
+ visibility: hidden;
34
+ }
35
+ }
36
+
37
+ nav {
38
+ display: flex;
39
+
40
+ position: absolute;
41
+ z-index: 10000;
42
+ bottom: 0;
43
+ left: 0;
44
+ right: 0;
45
+ opacity: 0.8;
46
+ }
47
+
48
+ nav:hover, nav:focus-within {
49
+ opacity: 1;
50
+ }
51
+
52
+ @media print {
53
+ nav {
54
+ display: none;
55
+ }
56
+
57
+ /* Prevent parts of slides from being cut off on Firefox */
58
+ .remark-slide-scaler {
59
+ transform: none !important;
60
+ }
61
+ }
62
+
63
+ </style>
64
+ <link rel="stylesheet" href="{{ 'assets/style_only_syntax.css' | relative_url }}" />
65
+ </head>
66
+ <body>
67
+ </body>
68
+ <script src="{{ 'assets/plugin/remark_presenter/remark.min.js' | relative_url }}"></script>
69
+ </html>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="512" height="512" version="1.1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
3
+ <defs>
4
+ <filter id="filter7674" x="-.25" y="-.25" width="1.5" height="1.5" color-interpolation-filters="sRGB">
5
+ <feGaussianBlur stdDeviation="12.0308382"/>
6
+ </filter>
7
+ </defs>
8
+ <g>
9
+ <path d="m122.52 34.551-94.311 117.48 4.503 246.11 127.26 70.081 258.18-41.737 71.954-66.215-38.507-266.18s-1.2406-30.237-85.384-44.738-243.69-14.797-243.69-14.797z" fill="#9300cf" filter="url(#filter7674)" transform="scale(1.01) rotate(30deg) translate(2, 10)" transform-origin="center"/>
10
+ <path d="m122.52 34.551-94.311 117.48 4.503 246.11 127.26 70.081 258.18-41.737 71.954-66.215-38.507-266.18s-1.2406-30.237-85.384-44.738-243.69-14.797-243.69-14.797z" fill="#f61616"/>
11
+ </g>
12
+ </svg>
@@ -62,6 +62,22 @@ var UrlHelper = {
62
62
  return url.substring(hashLoc, argsStart);
63
63
  },
64
64
 
65
+ // Replace an existing hash with a [newHash]. The new hash
66
+ //
67
+ withReplacedHash(url, newHash) {
68
+ let hashLoc = url.lastIndexOf('#');
69
+
70
+ if ((newHash + "").charAt(0) != '#') {
71
+ newHash = `#${newHash}`;
72
+ }
73
+
74
+ if (hashLoc == -1) {
75
+ return url + newHash;
76
+ }
77
+
78
+ return url.substring(0, hashLoc) + newHash;
79
+ },
80
+
65
81
  /// Remove metadata encoded in the given URL and returns
66
82
  /// it.
67
83
  /// If [url] is undefined, uses the page's URL.
@@ -115,4 +131,8 @@ assertEq("Trimming metadata",
115
131
  "https://example.com/"
116
132
  );
117
133
 
134
+ assertEq("Replacing a hash",
135
+ UrlHelper.withReplacedHash("https://example.com/#foo", "bar"),
136
+ "https://example.com/#bar");
137
+
118
138
  export default UrlHelper;
@@ -51,7 +51,8 @@ function expandBasedOnURL() {
51
51
  const doExpansion = (url) => {
52
52
  // Determine the hash.
53
53
  let hash = UrlHelper.getPageHash();
54
- if (hash == null) {
54
+ let isInvalid = hash && /^\#\d+/.exec(hash);
55
+ if (hash == null || isInvalid) {
55
56
  return;
56
57
  }
57
58
 
@@ -0,0 +1,164 @@
1
+ import { getUrlQuery, Searcher } from "../search.mjs";
2
+ import { stringLookup } from "../strings.mjs";
3
+ import UrlHelper from "../UrlHelper.mjs";
4
+
5
+ function isInPresenterMode(targetDoc) {
6
+ return targetDoc.body.classList.contains("remark-presenter-mode");
7
+ }
8
+
9
+ function focusSearchResult(targetWin, query, targetMatchNo, slideshow, searcher) {
10
+ let matchesFound = 0;
11
+ for (const slide of slideshow.getSlides()) {
12
+ let targetText = (slide.content ?? []).join("\n");
13
+ let currentSlideNo = slide.getSlideIndex() + 1;
14
+
15
+ matchesFound += searcher.getNumberOfMatches(query, targetText);
16
+ console.log("Considering ", targetText, " with ", matchesFound, "matches found so far");
17
+
18
+ if (matchesFound > targetMatchNo) {
19
+ slideshow.gotoSlide(currentSlideNo);
20
+ return;
21
+ }
22
+
23
+ // Now search the notes!
24
+ if (slide.notes) {
25
+ targetText = slide.notes.join("\n");
26
+ matchesFound += searcher.getNumberOfMatches(query, targetText);
27
+ if (matchesFound > targetMatchNo) {
28
+ slideshow.gotoSlide(currentSlideNo);
29
+
30
+ if (!isInPresenterMode(targetWin.document)) {
31
+ slideshow.togglePresenterMode();
32
+ }
33
+ return;
34
+ }
35
+ }
36
+ }
37
+
38
+ console.log("Found ", matchesFound, " matches, which is less than the target of ", targetMatchNo);
39
+ slideshow.gotoLastSlide();
40
+ return -1;
41
+ }
42
+
43
+ /// Show a search result the user requested through the
44
+ /// page's URL.
45
+ function focusSearchResultFromUrl(targetWin, slideshow) {
46
+ let { query, resultIndex } = getUrlQuery() ?? {};
47
+ let index = resultIndex;
48
+
49
+ if (query === undefined || index === undefined) {
50
+ return;
51
+ }
52
+
53
+ console.log("Focusing a search result: ", query, index);
54
+
55
+ let searcher = new Searcher();
56
+ focusSearchResult(targetWin, query, index, slideshow, searcher);
57
+ }
58
+
59
+ function focusSlideFromHash(slideshow) {
60
+ let hash = UrlHelper.getPageHash();
61
+ if (!hash) {
62
+ return;
63
+ }
64
+
65
+ let targetSlide = parseInt(hash.substring(1));
66
+ if (targetSlide) {
67
+ console.log("Navigating to slide", targetSlide);
68
+ slideshow.gotoSlide(targetSlide);
69
+ }
70
+ }
71
+
72
+ async function main(targetWindow, config) {
73
+ if (!targetWindow.remark) {
74
+ // Wait for page load if remark isn't available yet.
75
+ await (new Promise(resolve => {
76
+ targetWindow.addEventListener('load', resolve);
77
+ }));
78
+ }
79
+
80
+ // See https://remarkjs.com/#8
81
+ let slideshow = targetWindow.remark.create(config);
82
+
83
+ // For debugging
84
+ window.slideshow_debug = slideshow;
85
+
86
+ targetWindow.focus();
87
+
88
+ addExtendedControls(targetWindow, slideshow);
89
+ focusSearchResultFromUrl(targetWindow, slideshow);
90
+
91
+ targetWindow.history.replaceState(null, targetWindow.location.href);
92
+ let targetWinHistory = targetWindow.history.state;
93
+
94
+ focusSlideFromHash(slideshow);
95
+
96
+ window.addEventListener('hashchange', () => {
97
+ focusSlideFromHash(slideshow);
98
+ });
99
+
100
+ slideshow.on('showSlide', function(newSlide) {
101
+ if (!newSlide) {
102
+ return;
103
+ }
104
+ let hashId = newSlide.getSlideIndex() + 1;
105
+
106
+ // Update the window's URL to match that of the interior
107
+ // (e.g. slide 3 = #3).
108
+ // Try not to have the forward/back arrows go forward/back in the iframe's history.
109
+ targetWindow.history.replaceState(
110
+ targetWinHistory,
111
+ UrlHelper.withReplacedHash(targetWindow.location.href, hashId));
112
+ window.location.hash = hashId;
113
+ });
114
+ }
115
+
116
+ /// Apply minor adjustments to the default remark layout
117
+ function addExtendedControls(targetWindow, slideshow) {
118
+ let slideContainer = targetWindow.document.querySelector(".remark-slides-area");
119
+
120
+ // Announce changes to the slide (e.g. going to the next slide).
121
+ slideContainer.setAttribute("aria-live", "polite");
122
+
123
+ // Add next/previous buttons
124
+ let nextSlideBtn = targetWindow.document.createElement("button");
125
+ let prevSlideBtn = targetWindow.document.createElement("button");
126
+ let printBtn = targetWindow.document.createElement("button");
127
+ let spacer = targetWindow.document.createElement("div");
128
+
129
+ let nav = targetWindow.document.createElement("nav");
130
+
131
+ nextSlideBtn.innerText = stringLookup('btn_next_slide');
132
+ prevSlideBtn.innerText = stringLookup('btn_prev_slide');
133
+ printBtn.innerText = stringLookup('btn_print');
134
+
135
+ spacer.style.flexGrow = 1;
136
+
137
+ nextSlideBtn.onclick = () => {
138
+ slideshow.gotoNextSlide();
139
+ };
140
+
141
+ prevSlideBtn.onclick = () => {
142
+ slideshow.gotoPreviousSlide();
143
+ };
144
+
145
+ printBtn.onclick = () => {
146
+ targetWindow.print();
147
+ };
148
+
149
+ slideshow.on('showSlide', function(newSlide) {
150
+ if (!newSlide) {
151
+ return;
152
+ }
153
+
154
+ prevSlideBtn.disabled = (newSlide.getSlideIndex() == 0);
155
+ nextSlideBtn.disabled = (newSlide.getSlideIndex() + 1 >= slideshow.getSlideCount());
156
+ });
157
+
158
+
159
+
160
+ nav.replaceChildren(prevSlideBtn, nextSlideBtn, spacer, printBtn);
161
+ targetWindow.document.body.appendChild(nav);
162
+ }
163
+
164
+ export default { start: main };