hematite 0.0.9 → 0.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d623b260279dabc636598983bebf15e547d963ead82e21b5e8357572597bb48
4
- data.tar.gz: 00bba21df3b38ea1db9bf57d631b3ce2da97c5f077c0680831550192cc4c58d7
3
+ metadata.gz: 8ba3735a0bf64aa9c895fc9622e0370b0827c80386469ccb4c5172058f91db97
4
+ data.tar.gz: e6f824c10b0febde44d427ee0528681f756cc59bff67a3362e256d77d5be3650
5
5
  SHA512:
6
- metadata.gz: 51bc1b4fbea55a7bf316d03ac9c291c3f233ab7e91fe163dd3412f23518e3f4b247c3aeafd0cc1b72bb941ec3f721b90dc949bed6cfb3572ee8a4b6ae5fff182
7
- data.tar.gz: fe620903b815435c84c0a2d45b3edb1ca10c9d2727eb129ca24c0837b55adbf5fc384086feb0228b164084616419048fec8df8c62138ad976d4a8db990a1d79b
6
+ metadata.gz: 958067abc2e83cbecc509dc7c31c2eb711c2116ea201a27c28f6a89bc0f0a6658d34532433596b989178ab070d686c2a5de0d26781ff6b92d73fdc6416f9608f
7
+ data.tar.gz: e01cb8c28899e24135e832ef89543c9266e66db13d9a53f40327d6c32b6d8ed815d5da7247a63fd88ca94dc762180ab752fb8494c2d9e31d3ae2ed13fdda6297
data/_config.yml CHANGED
@@ -1,9 +1,6 @@
1
1
 
2
2
  # Settings for the demo site.
3
3
  # `jekyll serve` does not auto-reload this file.
4
- #
5
- # See https://leo3418.github.io/collections/multilingual-jekyll-site/localize-strings
6
- # for how localization works.
7
4
 
8
5
  title: Hematite Theme
9
6
  description: A Jekyll theme intended for course websites
@@ -12,6 +9,9 @@ permalink: pretty
12
9
  hematite:
13
10
  auto_invert_imgs: true
14
11
 
12
+ # Set to true to minimize the header by default
13
+ minimize_header: false
14
+
15
15
  # Date options are as specified here:
16
16
  # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
17
17
  date_format:
@@ -0,0 +1,101 @@
1
+ <!--
2
+ See assets/html/settings.html. This file can be included
3
+ in your own settings page and add your settings to it!
4
+ -->
5
+
6
+ <!-- So they can be localized, much of this page is filled by JavaScript -->
7
+ <!-- Organization inspired by https://www.w3.org/WAI/tutorials/forms/grouping/ -->
8
+ <fieldset>
9
+ <legend id="font_legend">settings_font_legend</legend>
10
+ <div>
11
+ <label id="font_family_lbl" for="font_family">settings_font_family_label</label>
12
+ <select id="font_family"></select>
13
+ </div>
14
+ <div>
15
+ <label id="font_size_lbl" for="font_size">settings_font_size_label</label>
16
+ <select id="font_size">
17
+ </select>
18
+ </div>
19
+ </fieldset>
20
+
21
+ <fieldset>
22
+ <legend id="theme_legend">page_theme_legend</legend>
23
+ <div>
24
+ <label id="page_theme_lbl" for="page_theme">settings_theme_label</label>
25
+ <select id="page_theme"></select>
26
+ </div>
27
+ <div>
28
+ <label id="page_minimize_header_lbl" for="minimize_page_hdr">settings_minimize_header</label>
29
+ <input type="checkbox" id="minimize_page_hdr"/>
30
+ </div>
31
+ </fieldset>
32
+
33
+ <script type="module">
34
+ import Settings from "{{ 'assets/js/Settings.mjs' | relative_url }}";
35
+ import { stringLookup } from "{{ 'assets/js/strings.mjs' | relative_url }}";
36
+
37
+ let settingsTextElemIDs = [
38
+ `settings_header`, `settings_description`, `font_legend`,
39
+ `font_family_lbl`, `font_size_lbl`, `theme_legend`,
40
+ `page_theme_lbl`, `page_minimize_header_lbl`,
41
+ ];
42
+
43
+ // Localize all descriptive settings elements (each should contian the
44
+ // name of its localization key).
45
+ for (const id of settingsTextElemIDs) {
46
+ let elem = document.querySelector(`#${id}`);
47
+
48
+ if (elem) {
49
+ elem.innerText = stringLookup(elem.innerText);
50
+ }
51
+ }
52
+
53
+ let fontSizeSelect = document.querySelector("#font_size");
54
+ let fontFamilySelect = document.querySelector("#font_family");
55
+ let pageThemeSelect = document.querySelector("#page_theme");
56
+ let minimizeHeaderCheckbox = document.querySelector("#minimize_page_hdr");
57
+
58
+ pageThemeSelect.innerHTML =
59
+ `
60
+ <option value='${Settings.THEME_AUTO}'>${stringLookup('page_theme_auto')}</option>
61
+ <option value='${Settings.THEME_DARK}'>${stringLookup('page_theme_dark')}</option>
62
+ <option value='${Settings.THEME_LIGHT}'>${stringLookup('page_theme_light')}</option>
63
+ `;
64
+
65
+ fontFamilySelect.innerHTML =
66
+ `
67
+ <option value='${Settings.FONT_DEFAULT}'>${stringLookup('page_font_default')}</option>
68
+ <option value='${Settings.FONT_SERIF}'>${stringLookup('page_font_serif')}</option>
69
+ <option value='${Settings.FONT_SANS}'>${stringLookup('page_font_sans')}</option>
70
+ `;
71
+
72
+ fontSizeSelect.innerHTML =
73
+ `
74
+ <option value='${Settings.FONT_SIZE_DEFAULT}'>${stringLookup('page_font_default')}</option>
75
+ <option value='${Settings.FONT_SIZE_SMALL}'>${stringLookup('page_font_small')}</option>
76
+ <option value='${Settings.FONT_SIZE_MEDIUM}'>${stringLookup('page_font_medium')}</option>
77
+ <option value='${Settings.FONT_SIZE_LARGE}'>${stringLookup('page_font_large')}</option>
78
+ `;
79
+
80
+ fontSizeSelect.oninput = () => {
81
+ Settings.setFontSize(fontSizeSelect.value);
82
+ };
83
+
84
+ fontFamilySelect.oninput = () => {
85
+ Settings.setFontFamily(fontFamilySelect.value);
86
+ };
87
+
88
+ pageThemeSelect.oninput = () => {
89
+ Settings.setTheme(pageThemeSelect.value);
90
+ };
91
+
92
+ minimizeHeaderCheckbox.oninput = () => {
93
+ Settings.setHeaderMinimized(minimizeHeaderCheckbox.checked);
94
+ };
95
+
96
+ pageThemeSelect.value = Settings.getTheme();
97
+ fontFamilySelect.value = Settings.getFontFamily();
98
+ fontSizeSelect.value = Settings.getFontSize();
99
+ minimizeHeaderCheckbox.checked = Settings.getHeaderMinimized();
100
+
101
+ </script>
data/_sass/_elements.scss CHANGED
@@ -149,3 +149,31 @@ a.settings-btn {
149
149
  border: 1px solid var(--line-color-light);
150
150
  }
151
151
  }
152
+
153
+ // Invert while trying to preserve color hue.
154
+ @mixin img-invert {
155
+ filter: invert(1) hue-rotate(180deg);
156
+ }
157
+
158
+ @media (prefers-color-scheme: dark) {
159
+ :root:not(.lightTheme) main img.auto-invert {
160
+ @include img-invert;
161
+ }
162
+ }
163
+
164
+ :root.darkTheme main img.auto-invert {
165
+ @include img-invert;
166
+ }
167
+
168
+ // Users can `include' this to invert images automatically in dark mode.
169
+ @mixin auto-invert-images {
170
+ @media (prefers-color-scheme: dark) {
171
+ :root:not(.lightTheme) main img:not(.no-invert) {
172
+ @include img-invert;
173
+ }
174
+ }
175
+
176
+ :root.darkTheme main img:not(.no-invert) {
177
+ @include img-invert;
178
+ }
179
+ }
data/_sass/_nav.scss CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  $header-z-index: 100;
4
4
 
5
- header {
5
+ body > header {
6
6
  position: sticky;
7
7
  top: 0;
8
8
  z-index: $header-z-index;
@@ -41,6 +41,33 @@ header {
41
41
  }
42
42
  }
43
43
 
44
+ :root.minimizedNavHeader body > header {
45
+ > *:not(#toggle_sidebar_btn) {
46
+ opacity: 0;
47
+ display: inline-block;
48
+ transition: opacity 0.5s ease;
49
+ }
50
+
51
+ word-wrap: break-word;
52
+ width: var(--header-height);
53
+ padding: 0;
54
+ transition: width 0.5s ease;
55
+
56
+ position: fixed;
57
+
58
+ // The minimizedNavHeader class is added after page load. Make the
59
+ // transition less jarring.
60
+ animation: grow-in 0.5s ease 1;
61
+ }
62
+
63
+ :root.minimizedNavHeader.hasOpenSidebar body > header {
64
+ > *:not(#toggle_sidebar_btn) {
65
+ opacity: 1;
66
+ }
67
+
68
+ width: calc(var(--nav-width) + #{2 * $navbar-padding});
69
+ }
70
+
44
71
  nav.sidebar {
45
72
  position: fixed;
46
73
  top: var(--header-height);
@@ -58,7 +85,7 @@ nav.sidebar {
58
85
  color: var(--primary-text-color);
59
86
  background-color: var(--primary-background-color);
60
87
  box-shadow: 0 0 2px var(--shadow-color-light);
61
- padding: 10px;
88
+ padding: $navbar-padding;
62
89
 
63
90
  z-index: $header-z-index - 1;
64
91
 
data/_sass/_sizes.scss CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  $site-content-preferred-width: 700px;
3
3
  $content-main-padding: 30px;
4
+ $navbar-padding: 10px;
4
5
 
5
6
  // CSS variables
6
7
  :root {
@@ -6,89 +6,7 @@ noindex: true
6
6
 
7
7
  <noscript>JavaScript is required to view this page's content!</noscript>
8
8
 
9
- <!-- So they can be localized, much of this page is filled by JavaScript -->
10
9
  <h1 id="settings_header">page_settings_header</h1>
11
10
  <p id="settings_description">page_settings_description</p>
12
11
 
13
- <!-- Organization inspired by https://www.w3.org/WAI/tutorials/forms/grouping/ -->
14
- <fieldset>
15
- <legend id="font_legend">settings_font_legend</legend>
16
- <div>
17
- <label id="font_family_lbl" for="font_family">settings_font_family_label</label>
18
- <select id="font_family"></select>
19
- </div>
20
- <div>
21
- <label id="font_size_lbl" for="font_size">settings_font_size_label</label>
22
- <select id="font_size">
23
- </select>
24
- </div>
25
- </fieldset>
26
-
27
- <fieldset>
28
- <legend id="theme_legend">page_theme_legend</legend>
29
- <div>
30
- <label id="page_theme_lbl" for="page_theme">settings_theme_label</label>
31
- <select id="page_theme"></select>
32
- </div>
33
- </fieldset>
34
-
35
- <script type="module">
36
- import Settings from "{{ 'assets/js/Settings.mjs' | relative_url }}";
37
- import { stringLookup } from "{{ 'assets/js/strings.mjs' | relative_url }}";
38
-
39
- let settingsTextElemIDs = [
40
- `settings_header`, `settings_description`, `font_legend`,
41
- `font_family_lbl`, `font_size_lbl`, `theme_legend`,
42
- `page_theme_lbl`,
43
- ];
44
-
45
- // Localize all descriptive settings elements (each should contian the
46
- // name of its localization key).
47
- for (const id of settingsTextElemIDs) {
48
- let elem = document.querySelector(`#${id}`);
49
- elem.innerText = stringLookup(elem.innerText);
50
- }
51
-
52
- let fontSizeSelect = document.querySelector("#font_size");
53
- let fontFamilySelect = document.querySelector("#font_family");
54
- let pageThemeSelect = document.querySelector("#page_theme");
55
-
56
- pageThemeSelect.innerHTML =
57
- `
58
- <option value='${Settings.THEME_AUTO}'>${stringLookup('page_theme_auto')}</option>
59
- <option value='${Settings.THEME_DARK}'>${stringLookup('page_theme_dark')}</option>
60
- <option value='${Settings.THEME_LIGHT}'>${stringLookup('page_theme_light')}</option>
61
- `;
62
-
63
- fontFamilySelect.innerHTML =
64
- `
65
- <option value='${Settings.FONT_DEFAULT}'>${stringLookup('page_font_default')}</option>
66
- <option value='${Settings.FONT_SERIF}'>${stringLookup('page_font_serif')}</option>
67
- <option value='${Settings.FONT_SANS}'>${stringLookup('page_font_sans')}</option>
68
- `;
69
-
70
- fontSizeSelect.innerHTML =
71
- `
72
- <option value='${Settings.FONT_SIZE_DEFAULT}'>${stringLookup('page_font_default')}</option>
73
- <option value='${Settings.FONT_SIZE_SMALL}'>${stringLookup('page_font_small')}</option>
74
- <option value='${Settings.FONT_SIZE_MEDIUM}'>${stringLookup('page_font_medium')}</option>
75
- <option value='${Settings.FONT_SIZE_LARGE}'>${stringLookup('page_font_large')}</option>
76
- `;
77
-
78
- fontSizeSelect.oninput = () => {
79
- Settings.setFontSize(fontSizeSelect.value);
80
- };
81
-
82
- fontFamilySelect.oninput = () => {
83
- Settings.setFontFamily(fontFamilySelect.value);
84
- };
85
-
86
- pageThemeSelect.oninput = () => {
87
- Settings.setTheme(pageThemeSelect.value);
88
- };
89
-
90
- pageThemeSelect.value = Settings.getTheme();
91
- fontFamilySelect.value = Settings.getFontFamily();
92
- fontSizeSelect.value = Settings.getFontSize();
93
-
94
- </script>
12
+ {% include settings.html %}
@@ -1,5 +1,9 @@
1
1
  ---
2
2
  ---
3
+ import AsyncUtil from "./AsyncUtil.mjs";
4
+ import AnimationUtil from "./AnimationUtil.mjs";
5
+
6
+ const THEME_TRANSITION_TIME = 500; // ms
3
7
 
4
8
  class Settings {
5
9
  THEME_AUTO = 'auto';
@@ -18,6 +22,7 @@ class Settings {
18
22
  FONT_SIZE_KEY_ = 'hematite-setting-font-size';
19
23
  FONT_FAMILY_KEY_ = 'hematite-setting-font-family';
20
24
  THEME_KEY_ = 'hematite-setting-theme';
25
+ HEADER_MINIMIZED_KEY_ = 'hematite-setting-minimize-header';
21
26
 
22
27
  constructor() {
23
28
  }
@@ -43,6 +48,12 @@ class Settings {
43
48
  return this.getSetting_(this.FONT_SIZE_KEY_) ?? this.FONT_SIZE_DEFAULT;
44
49
  }
45
50
 
51
+ getHeaderMinimized() {
52
+ let minimizedStr = this.getSetting_(this.HEADER_MINIMIZED_KEY_)
53
+ ?? {{ site.hematite.user_config.minimize_header | default: site.hematite.minimize_header | default: "false" | jsonify }};
54
+ return minimizedStr == "true";
55
+ }
56
+
46
57
  setFontSize(sizeOption) {
47
58
  this.setSetting_(this.FONT_SIZE_KEY_, sizeOption);
48
59
  }
@@ -55,6 +66,10 @@ class Settings {
55
66
  this.setSetting_(this.THEME_KEY_, themeOption);
56
67
  }
57
68
 
69
+ setHeaderMinimized(minimize) {
70
+ this.setSetting_(this.HEADER_MINIMIZED_KEY_, `${minimize}`);
71
+ }
72
+
58
73
  getFontSizePt_() {
59
74
  let fontSizeOption = this.getFontSize();
60
75
 
@@ -87,7 +102,9 @@ class Settings {
87
102
  return this.getTheme() == this.THEME_LIGHT;
88
103
  }
89
104
 
90
- applySettings() {
105
+ async applySettings() {
106
+ document.documentElement.classList.add("changingTheme");
107
+
91
108
  // Clean up previous changes. We might be re-applying styles.
92
109
  document.documentElement.classList.remove("lightTheme");
93
110
  document.documentElement.classList.remove("darkTheme");
@@ -99,7 +116,12 @@ class Settings {
99
116
  }
100
117
 
101
118
 
102
- let styleHTML = '';
119
+ let styleHTML =
120
+ `
121
+ :root.changingTheme * {
122
+ transition: ${THEME_TRANSITION_TIME}ms ease all;
123
+ }
124
+ `;
103
125
 
104
126
  // Font family
105
127
  if (this.usingNonDefaultFontFamily_()) {
@@ -121,6 +143,9 @@ class Settings {
121
143
  `;
122
144
  }
123
145
 
146
+ this.style_.innerHTML = styleHTML;
147
+ document.documentElement.appendChild(this.style_);
148
+
124
149
  // Theme
125
150
  if (this.forcingDarkTheme_()) {
126
151
  document.documentElement.classList.add("darkTheme");
@@ -129,8 +154,29 @@ class Settings {
129
154
  document.documentElement.classList.add("lightTheme");
130
155
  }
131
156
 
132
- this.style_.innerHTML = styleHTML;
133
- document.documentElement.appendChild(this.style_);
157
+ if (this.getHeaderMinimized()) {
158
+ // Run roughly in parallel
159
+ (async () => {
160
+ let header = document.querySelector("body > header");
161
+ if (header) {
162
+ await AnimationUtil.collapseOutVert(header, THEME_TRANSITION_TIME / 2);
163
+ }
164
+
165
+ document.documentElement.classList.add("minimizedNavHeader");
166
+
167
+ if (header) {
168
+ // Re-show the header
169
+ // Rely on a CSS animation for animating the header's return.
170
+ await AnimationUtil.expandInVert(header, 0);
171
+ }
172
+ })();
173
+ }
174
+ else {
175
+ document.documentElement.classList.remove("minimizedNavHeader");
176
+ }
177
+
178
+ await AsyncUtil.waitMillis(THEME_TRANSITION_TIME);
179
+ document.documentElement.classList.remove("changingTheme");
134
180
  }
135
181
  }
136
182
 
data/assets/js/main.mjs CHANGED
@@ -17,7 +17,7 @@ addEventListener("load", () => {
17
17
  // After loading elements, but before loading elements like images.
18
18
  addEventListener("DOMContentLoaded", () => {
19
19
  handleSidebar();
20
-
21
- // Apply user-specified settings
22
- Settings.applySettings();
23
20
  });
21
+
22
+ // Apply user-specified settings
23
+ Settings.applySettings();
@@ -17,11 +17,11 @@ function handleSidebar() {
17
17
  const setSidebarOpen = (open) => {
18
18
  if (!open) {
19
19
  sidebar.classList.remove(`open`);
20
- document.scrollingElement?.classList.remove(`hasOpenSidebar`);
20
+ document.documentElement.classList.remove(`hasOpenSidebar`);
21
21
  }
22
22
  else {
23
23
  sidebar.classList.add(`open`);
24
- document.scrollingElement?.classList.add(`hasOpenSidebar`);
24
+ document.documentElement.classList.add(`hasOpenSidebar`);
25
25
  }
26
26
  };
27
27
 
@@ -51,4 +51,5 @@ export default {
51
51
  page_theme_auto: 'Automatic',
52
52
  page_theme_dark: 'Dark Theme',
53
53
  page_theme_light: 'Light Theme',
54
+ settings_minimize_header: 'Hide Header: '
54
55
  };
@@ -49,4 +49,5 @@ export default {
49
49
  page_theme_auto: 'Automático',
50
50
  page_theme_dark: 'Oscuro',
51
51
  page_theme_light: 'Brillante',
52
+ settings_minimize_header: 'Título escondido: '
52
53
  };
data/assets/style.scss CHANGED
@@ -6,10 +6,6 @@ styles: true
6
6
  @import "hematite";
7
7
 
8
8
  {% if site.hematite.auto_invert_imgs %}
9
- // Auto-invert images in dark mode!
10
- @media (prefers-color-scheme: dark) {
11
- main img:not(.no-invert) {
12
- filter: invert(1) hue-rotate(180deg);
13
- }
14
- }
9
+ // In dark mode, invert the brightness of images
10
+ @include auto-invert-images;
15
11
  {% endif %}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hematite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henry Heino
@@ -43,6 +43,7 @@ files:
43
43
  - _includes/nav/pages_list.html
44
44
  - _includes/nav/pinned_page.html
45
45
  - _includes/nav/sidebar.html
46
+ - _includes/settings.html
46
47
  - _layouts/calendar.html
47
48
  - _layouts/default.html
48
49
  - _layouts/home.html