jekyll-theme-chirpy 6.5.5 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -6
  3. data/_data/origin/basic.yml +3 -10
  4. data/_data/origin/cors.yml +26 -31
  5. data/_includes/analytics/cloudflare.html +7 -0
  6. data/_includes/analytics/goatcounter.html +6 -0
  7. data/_includes/analytics/google.html +13 -0
  8. data/_includes/analytics/matomo.html +14 -0
  9. data/_includes/analytics/umami.html +6 -0
  10. data/_includes/comments/disqus.html +5 -5
  11. data/_includes/comments/giscus.html +3 -3
  12. data/_includes/comments/utterances.html +4 -5
  13. data/_includes/comments.html +3 -3
  14. data/_includes/embed/audio.html +35 -0
  15. data/_includes/embed/bilibili.html +3 -4
  16. data/_includes/embed/video.html +59 -0
  17. data/_includes/embed/youtube.html +1 -1
  18. data/_includes/footer.html +8 -1
  19. data/_includes/head.html +21 -25
  20. data/_includes/js-selector.html +31 -37
  21. data/_includes/lang.html +3 -1
  22. data/_includes/{img-url.html → media-url.html} +8 -8
  23. data/_includes/mermaid.html +31 -27
  24. data/_includes/mode-toggle.html +24 -51
  25. data/_includes/pageviews/goatcounter.html +19 -0
  26. data/_includes/post-description.html +16 -0
  27. data/_includes/refactor-content.html +1 -1
  28. data/_includes/related-posts.html +2 -4
  29. data/_includes/search-loader.html +1 -1
  30. data/_includes/search-results.html +1 -1
  31. data/_includes/sidebar.html +2 -2
  32. data/_includes/toc.html +2 -2
  33. data/_includes/topbar.html +1 -1
  34. data/_layouts/compress.html +2 -2
  35. data/_layouts/default.html +3 -8
  36. data/_layouts/home.html +2 -5
  37. data/_layouts/post.html +17 -4
  38. data/_sass/addon/commons.scss +38 -46
  39. data/_sass/colors/typography-dark.scss +0 -4
  40. data/_sass/dist/bootstrap.css +5 -0
  41. data/_sass/layout/post.scss +23 -10
  42. data/_sass/main.bundle.scss +2 -0
  43. data/assets/css/jekyll-theme-chirpy.scss +5 -1
  44. data/assets/feed.xml +1 -8
  45. data/assets/js/data/mathjax.js +25 -0
  46. data/assets/js/data/swconf.js +0 -14
  47. data/assets/js/dist/app.min.js +4 -0
  48. data/assets/js/dist/categories.min.js +2 -2
  49. data/assets/js/dist/commons.min.js +2 -2
  50. data/assets/js/dist/home.min.js +2 -2
  51. data/assets/js/dist/misc.min.js +2 -2
  52. data/assets/js/dist/page.min.js +2 -2
  53. data/assets/js/dist/post.min.js +2 -2
  54. data/assets/js/dist/sw.min.js +5 -0
  55. metadata +22 -12
  56. data/_includes/goatcounter.html +0 -8
  57. data/_includes/google-analytics.html +0 -14
  58. data/assets/js/pwa/app.js +0 -54
  59. data/assets/js/pwa/sw.js +0 -101
data/_includes/lang.html CHANGED
@@ -1,7 +1,9 @@
1
1
  {% comment %}
2
2
  Detect appearance language and return it through variable "lang"
3
3
  {% endcomment %}
4
- {% if site.data.locales[site.lang] %}
4
+ {% if site.data.locales[page.lang] %}
5
+ {% assign lang = page.lang %}
6
+ {% elsif site.data.locales[site.lang] %}
5
7
  {% assign lang = site.lang %}
6
8
  {% else %}
7
9
  {% assign lang = 'en' %}
@@ -1,25 +1,25 @@
1
1
  {%- comment -%}
2
- Generate image final URL based on `site.img_cdn`, `page.img_path`
2
+ Generate media resource final URL based on `site.cdn`, `page.media_subpath`
3
3
 
4
4
  Arguments:
5
- src - required, basic image path
6
- img_path - optional, relative path of image
5
+ src - required, basic media resources path
6
+ subpath - optional, relative path of media resources
7
7
  absolute - optional, boolean, if true, generate absolute URL
8
8
 
9
9
  Return:
10
- image URL
10
+ media resources URL
11
11
  {%- endcomment -%}
12
12
 
13
13
  {% assign url = include.src %}
14
14
 
15
15
  {%- if url -%}
16
16
  {% unless url contains ':' %}
17
- {%- comment -%} Add page image path prefix {%- endcomment -%}
18
- {% assign url = include.img_path | default: '' | append: '/' | append: url %}
17
+ {%- comment -%} Add media resources subpath prefix {%- endcomment -%}
18
+ {% assign url = include.subpath | default: '' | append: '/' | append: url %}
19
19
 
20
20
  {%- comment -%} Prepend CND URL {%- endcomment -%}
21
- {% if site.img_cdn %}
22
- {% assign url = site.img_cdn | append: '/' | append: url %}
21
+ {% if site.cdn %}
22
+ {% assign url = site.cdn | append: '/' | append: url %}
23
23
  {% endif %}
24
24
 
25
25
  {% assign url = url | replace: '///', '/' | replace: '//', '/' | replace: ':/', '://' %}
@@ -1,29 +1,33 @@
1
1
  <!-- mermaid-js loader -->
2
2
  <script type="text/javascript">
3
- (function () {
4
- function updateMermaid(event) {
5
- if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
6
- const mode = event.data.message;
7
-
8
- if (typeof mermaid === 'undefined') {
9
- return;
10
- }
11
-
12
- let expectedTheme = mode === ModeToggle.DARK_MODE ? 'dark' : 'default';
13
- let config = { theme: expectedTheme };
14
-
15
- /* Re-render the SVG › <https://github.com/mermaid-js/mermaid/issues/311#issuecomment-332557344> */
16
- $('.mermaid').each(function () {
17
- let svgCode = $(this).prev().children().html();
18
- $(this).removeAttr('data-processed');
19
- $(this).html(svgCode);
20
- });
21
-
22
- mermaid.initialize(config);
23
- mermaid.init(undefined, '.mermaid');
3
+ function updateMermaid(event) {
4
+ if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
5
+ const mode = event.data.message;
6
+
7
+ if (typeof mermaid === 'undefined') {
8
+ return;
24
9
  }
10
+
11
+ let expectedTheme = mode === ModeToggle.DARK_MODE ? 'dark' : 'default';
12
+ let config = { theme: expectedTheme };
13
+
14
+ {%- comment -%}
15
+ Re-render the SVG › <https://github.com/mermaid-js/mermaid/issues/311#issuecomment-332557344>
16
+ {%- endcomment -%}
17
+ const mermaidList = document.getElementsByClassName('mermaid');
18
+
19
+ [...mermaidList].forEach((elem) => {
20
+ const svgCode = elem.previousSibling.children.item(0).innerHTML;
21
+ elem.innerHTML = svgCode;
22
+ elem.removeAttribute('data-processed');
23
+ });
24
+
25
+ mermaid.initialize(config);
26
+ mermaid.init(undefined, '.mermaid');
25
27
  }
28
+ }
26
29
 
30
+ (function () {
27
31
  let initTheme = 'default';
28
32
  const html = document.documentElement;
29
33
 
@@ -35,15 +39,16 @@
35
39
  }
36
40
 
37
41
  let mermaidConf = {
38
- theme: initTheme /* <default|dark|forest|neutral> */
42
+ theme: initTheme {%- comment -%} <default | dark | forest | neutral> {%- endcomment -%}
39
43
  };
40
44
 
41
- /* Create mermaid tag */
42
- document.querySelectorAll('pre>code.language-mermaid').forEach((elem) => {
45
+ {%- comment -%} Create mermaid tag {%- endcomment -%}
46
+ const basicList = document.getElementsByClassName('language-mermaid');
47
+ [...basicList].forEach((elem) => {
43
48
  const svgCode = elem.textContent;
44
49
  const backup = elem.parentElement;
45
- backup.classList.add('unloaded');
46
- /* create mermaid node */
50
+ backup.classList.add('d-none');
51
+ {%- comment -%} create mermaid node {%- endcomment -%}
47
52
  let mermaid = document.createElement('pre');
48
53
  mermaid.classList.add('mermaid');
49
54
  const text = document.createTextNode(svgCode);
@@ -52,7 +57,6 @@
52
57
  });
53
58
 
54
59
  mermaid.initialize(mermaidConf);
55
-
56
60
  window.addEventListener('message', updateMermaid);
57
61
  })();
58
62
  </script>
@@ -19,45 +19,32 @@
19
19
  }
20
20
 
21
21
  constructor() {
22
- if (this.hasMode) {
23
- if (this.isDarkMode) {
24
- if (!this.isSysDarkPrefer) {
25
- this.setDark();
26
- }
27
- } else {
28
- if (this.isSysDarkPrefer) {
29
- this.setLight();
30
- }
31
- }
32
- }
33
-
34
22
  let self = this;
35
23
 
36
- /* always follow the system prefers */
24
+ {%- comment -%} always follow the system prefers {%- endcomment -%}
37
25
  this.sysDarkPrefers.addEventListener('change', () => {
38
26
  if (self.hasMode) {
39
- if (self.isDarkMode) {
40
- if (!self.isSysDarkPrefer) {
41
- self.setDark();
42
- }
43
- } else {
44
- if (self.isSysDarkPrefer) {
45
- self.setLight();
46
- }
47
- }
48
-
49
27
  self.clearMode();
50
28
  }
51
-
52
29
  self.notify();
53
30
  });
54
- } /* constructor() */
31
+
32
+ if (!this.hasMode) {
33
+ return;
34
+ }
35
+
36
+ if (this.isDarkMode) {
37
+ this.setDark();
38
+ } else {
39
+ this.setLight();
40
+ }
41
+ }
55
42
 
56
43
  get sysDarkPrefers() {
57
44
  return window.matchMedia('(prefers-color-scheme: dark)');
58
45
  }
59
46
 
60
- get isSysDarkPrefer() {
47
+ get isPreferDark() {
61
48
  return this.sysDarkPrefers.matches;
62
49
  }
63
50
 
@@ -65,10 +52,6 @@
65
52
  return this.mode === ModeToggle.DARK_MODE;
66
53
  }
67
54
 
68
- get isLightMode() {
69
- return this.mode === ModeToggle.LIGHT_MODE;
70
- }
71
-
72
55
  get hasMode() {
73
56
  return this.mode != null;
74
57
  }
@@ -77,12 +60,12 @@
77
60
  return sessionStorage.getItem(ModeToggle.MODE_KEY);
78
61
  }
79
62
 
80
- /* get the current mode on screen */
63
+ {%- comment -%} get the current mode on screen {%- endcomment -%}
81
64
  get modeStatus() {
82
- if (this.isDarkMode || (!this.hasMode && this.isSysDarkPrefer)) {
83
- return ModeToggle.DARK_MODE;
65
+ if (this.hasMode) {
66
+ return this.mode;
84
67
  } else {
85
- return ModeToggle.LIGHT_MODE;
68
+ return this.isPreferDark ? ModeToggle.DARK_MODE : ModeToggle.LIGHT_MODE;
86
69
  }
87
70
  }
88
71
 
@@ -101,7 +84,9 @@
101
84
  sessionStorage.removeItem(ModeToggle.MODE_KEY);
102
85
  }
103
86
 
104
- /* Notify another plugins that the theme mode has changed */
87
+ {%- comment -%}
88
+ Notify another plugins that the theme mode has changed
89
+ {%- endcomment -%}
105
90
  notify() {
106
91
  window.postMessage(
107
92
  {
@@ -114,21 +99,9 @@
114
99
 
115
100
  flipMode() {
116
101
  if (this.hasMode) {
117
- if (this.isSysDarkPrefer) {
118
- if (this.isLightMode) {
119
- this.clearMode();
120
- } else {
121
- this.setLight();
122
- }
123
- } else {
124
- if (this.isDarkMode) {
125
- this.clearMode();
126
- } else {
127
- this.setDark();
128
- }
129
- }
102
+ this.clearMode();
130
103
  } else {
131
- if (this.isSysDarkPrefer) {
104
+ if (this.isPreferDark) {
132
105
  this.setLight();
133
106
  } else {
134
107
  this.setDark();
@@ -136,8 +109,8 @@
136
109
  }
137
110
 
138
111
  this.notify();
139
- } /* flipMode() */
140
- } /* ModeToggle */
112
+ }
113
+ }
141
114
 
142
115
  const modeToggle = new ModeToggle();
143
116
  </script>
@@ -0,0 +1,19 @@
1
+ <!-- Display GoatCounter pageviews -->
2
+ <script>
3
+ let pv = document.getElementById('pageviews');
4
+
5
+ if (pv !== null) {
6
+ const uri = location.pathname.replace(/\/$/, '');
7
+ const url = `https://{{ site.analytics.goatcounter.id }}.goatcounter.com/counter/${encodeURIComponent(uri)}.json`;
8
+
9
+ fetch(url)
10
+ .then((response) => response.json())
11
+ .then((data) => {
12
+ const count = data.count.replace(/\s/g, '');
13
+ pv.innerText = new Intl.NumberFormat().format(count);
14
+ })
15
+ .catch((error) => {
16
+ pv.innerText = '1';
17
+ });
18
+ }
19
+ </script>
@@ -0,0 +1,16 @@
1
+ {%- comment -%}
2
+ Get post description or generate it from the post content.
3
+ {%- endcomment -%}
4
+
5
+ {%- assign max_length = include.max_length | default: 200 -%}
6
+
7
+ {%- capture description -%}
8
+ {%- if post.description -%}
9
+ {{- post.description -}}
10
+ {%- else -%}
11
+ {%- include no-linenos.html content=post.content -%}
12
+ {{- content | markdownify | strip_html -}}
13
+ {%- endif -%}
14
+ {%- endcapture -%}
15
+
16
+ {{- description | strip | truncate: max_length | escape -}}
@@ -97,7 +97,7 @@
97
97
  {% assign _lazyload = true %}
98
98
 
99
99
  {%- capture _img_url -%}
100
- {% include img-url.html src=_src img_path=page.img_path %}
100
+ {% include media-url.html src=_src subpath=page.media_subpath %}
101
101
  {%- endcapture -%}
102
102
 
103
103
  {% assign _path_prefix = _img_url | remove: _src %}
@@ -21,6 +21,7 @@
21
21
  {% assign match_posts = match_posts | push: site.tags[tag] | uniq %}
22
22
  {% endfor %}
23
23
 
24
+ {% assign match_posts = match_posts | reverse %}
24
25
  {% assign last_index = match_posts.size | minus: 1 %}
25
26
  {% assign score_list = '' | split: '' %}
26
27
 
@@ -81,10 +82,7 @@
81
82
  {% include datetime.html date=post.date lang=include.lang %}
82
83
  <h4 class="pt-0 my-2">{{ post.title }}</h4>
83
84
  <div class="text-muted">
84
- <p>
85
- {% include no-linenos.html content=post.content %}
86
- {{ content | markdownify | strip_html | truncate: 200 | escape }}
87
- </p>
85
+ <p>{% include post-description.html %}</p>
88
86
  </div>
89
87
  </div>
90
88
  </a>
@@ -19,7 +19,7 @@
19
19
  {% capture not_found %}<p class="mt-5">{{ site.data.locales[include.lang].search.no_results }}</p>{% endcapture %}
20
20
 
21
21
  <script>
22
- /* Note: dependent library will be loaded in `js-selector.html` */
22
+ {%- comment -%} Note: dependent library will be loaded in `js-selector.html` {%- endcomment -%}
23
23
  SimpleJekyllSearch({
24
24
  searchInput: document.getElementById('search-input'),
25
25
  resultsContainer: document.getElementById('search-results'),
@@ -1,6 +1,6 @@
1
1
  <!-- The Search results -->
2
2
 
3
- <div id="search-result-wrapper" class="d-flex justify-content-center unloaded">
3
+ <div id="search-result-wrapper" class="d-flex justify-content-center d-none">
4
4
  <div class="col-11 content">
5
5
  <div id="search-hints">
6
6
  {% include_cached trending-tags.html %}
@@ -5,7 +5,7 @@
5
5
  <a href="{{ '/' | relative_url }}" id="avatar" class="rounded-circle">
6
6
  {%- if site.avatar != empty and site.avatar -%}
7
7
  {%- capture avatar_url -%}
8
- {% include img-url.html src=site.avatar %}
8
+ {% include media-url.html src=site.avatar %}
9
9
  {%- endcapture -%}
10
10
  <img src="{{- avatar_url -}}" width="112" height="112" alt="avatar" onerror="this.style.display='none'">
11
11
  {%- endif -%}
@@ -44,7 +44,7 @@
44
44
 
45
45
  <div class="sidebar-bottom d-flex flex-wrap align-items-center w-100">
46
46
  {% unless site.theme_mode %}
47
- <button type="button" class="mode-toggle btn" aria-label="Switch Mode">
47
+ <button type="button" class="btn btn-link nav-link" aria-label="Switch Mode" id="mode-toggle">
48
48
  <i class="fas fa-adjust"></i>
49
49
  </button>
50
50
 
data/_includes/toc.html CHANGED
@@ -6,8 +6,8 @@
6
6
  {% endif %}
7
7
 
8
8
  {% if enable_toc %}
9
- <section id="toc-wrapper" class="ps-0 pe-4">
10
- <h2 class="panel-heading ps-3 pt-2 mb-2">{{- site.data.locales[include.lang].panel.toc -}}</h2>
9
+ <section id="toc-wrapper" class="d-none ps-0 pe-4">
10
+ <h2 class="panel-heading ps-3 mb-2">{{- site.data.locales[include.lang].panel.toc -}}</h2>
11
11
  <nav id="toc"></nav>
12
12
  </section>
13
13
  {% endif %}
@@ -59,7 +59,7 @@
59
59
  <i class="fas fa-search fa-fw"></i>
60
60
  </button>
61
61
 
62
- <search class="align-items-center ms-3 ms-lg-0">
62
+ <search id="search" class="align-items-center ms-3 ms-lg-0">
63
63
  <i class="fas fa-search fa-fw"></i>
64
64
  <input
65
65
  class="form-control"
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  # Jekyll layout that compresses HTML
3
- # v3.1.0
3
+ # v3.2.0
4
4
  # http://jch.penibelst.de/
5
5
  # © 2014–2015 Anatol Broder
6
6
  # MIT License
7
7
  ---
8
8
 
9
9
  {% capture _LINE_FEED %}
10
- {% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "<!-- -->" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "</pre>" %}<pre{{ _pres.first }}</pre>{% endif %}{% unless _pre_before contains "</pre>" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %} <table id="compress_html_profile_{{ site.time | date: "%Y%m%d" }}" class="compress_html_profile"> <thead> <tr> <td>Step <td>Bytes <tbody> <tr> <td>raw <td>{{ content | size }}{% if _profile_endings %} <tr> <td>endings <td>{{ _profile_endings }}{% endif %}{% if _profile_startings %} <tr> <td>startings <td>{{ _profile_startings }}{% endif %}{% if _profile_comments %} <tr> <td>comments <td>{{ _profile_comments }}{% endif %}{% if _profile_collapse %} <tr> <td>collapse <td>{{ _profile_collapse }}{% endif %}{% if _profile_clippings %} <tr> <td>clippings <td>{{ _profile_clippings }}{% endif %} </table>{% endif %}{% endif %}
10
+ {% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" or page.compress_html == false %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "<!-- -->" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "</pre>" %}<pre{{ _pres.first }}</pre>{% endif %}{% unless _pre_before contains "</pre>" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %} <table id="compress_html_profile_{{ site.time | date: "%Y%m%d" }}" class="compress_html_profile"> <thead> <tr> <td>Step <td>Bytes <tbody> <tr> <td>raw <td>{{ content | size }}{% if _profile_endings %} <tr> <td>endings <td>{{ _profile_endings }}{% endif %}{% if _profile_startings %} <tr> <td>startings <td>{{ _profile_startings }}{% endif %}{% if _profile_comments %} <tr> <td>comments <td>{{ _profile_comments }}{% endif %}{% if _profile_collapse %} <tr> <td>collapse <td>{{ _profile_collapse }}{% endif %}{% if _profile_clippings %} <tr> <td>clippings <td>{{ _profile_clippings }}{% endif %} </table>{% endif %}{% endif %}
@@ -13,7 +13,7 @@ layout: compress
13
13
  {% endif %}
14
14
 
15
15
  <!-- `site.alt_lang` can specify a language different from the UI -->
16
- <html lang="{{ site.alt_lang | default: site.lang }}" {{ prefer_mode }}>
16
+ <html lang="{{ page.lang | default: site.alt_lang | default: site.lang }}" {{ prefer_mode }}>
17
17
  {% include head.html %}
18
18
 
19
19
  <body>
@@ -75,13 +75,8 @@ layout: compress
75
75
  {% endif %}
76
76
 
77
77
  <!-- JavaScripts -->
78
+ {% include js-selector.html lang=lang %}
78
79
 
79
- {% include js-selector.html %}
80
-
81
- {% if page.mermaid %}
82
- {% include mermaid.html %}
83
- {% endif %}
84
-
85
- {% include_cached search-loader.html %}
80
+ {% include_cached search-loader.html lang=lang %}
86
81
  </body>
87
82
  </html>
data/_layouts/home.html CHANGED
@@ -49,7 +49,7 @@ refactor: true
49
49
  {% if post.image %}
50
50
  {% assign src = post.image.path | default: post.image %}
51
51
  {% unless src contains '//' %}
52
- {% assign src = post.img_path | append: '/' | append: src | replace: '//', '/' %}
52
+ {% assign src = post.media_subpath | append: '/' | append: src | replace: '//', '/' %}
53
53
  {% endunless %}
54
54
 
55
55
  {% assign alt = post.image.alt | xml_escape | default: 'Preview Image' %}
@@ -72,10 +72,7 @@ refactor: true
72
72
  <h1 class="card-title my-2 mt-md-0">{{ post.title }}</h1>
73
73
 
74
74
  <div class="card-text content mt-0 mb-3">
75
- <p>
76
- {% include no-linenos.html content=post.content %}
77
- {{ content | markdownify | strip_html | truncate: 200 | escape }}
78
- </p>
75
+ <p>{% include post-description.html %}</p>
79
76
  </div>
80
77
 
81
78
  <div class="post-meta flex-grow-1 d-flex align-items-end">
data/_layouts/post.html CHANGED
@@ -14,6 +14,9 @@ tail_includes:
14
14
  <article class="px-1">
15
15
  <header>
16
16
  <h1 data-toc-skip>{{ page.title }}</h1>
17
+ {% if page.description %}
18
+ <p class="post-desc fw-light mb-4">{{ page.description }}</p>
19
+ {% endif %}
17
20
 
18
21
  <div class="post-meta text-muted">
19
22
  <!-- published date -->
@@ -74,12 +77,22 @@ tail_includes:
74
77
  </em>
75
78
  </span>
76
79
 
77
- <!-- read time -->
78
- {% include read-time.html content=content prompt=true lang=lang %}
80
+ <div>
81
+ <!-- pageviews -->
82
+ {% if site.pageviews.provider and site.analytics[site.pageviews.provider].id %}
83
+ <span>
84
+ <em id="pageviews">
85
+ <i class="fas fa-spinner fa-spin small"></i>
86
+ </em>
87
+ {{ site.data.locales[lang].post.pageview_measure }}
88
+ </span>
89
+ {% endif %}
90
+
91
+ <!-- read time -->
92
+ {% include read-time.html content=content prompt=true lang=lang %}
93
+ </div>
79
94
  </div>
80
- <!-- .d-flex -->
81
95
  </div>
82
- <!-- .post-meta -->
83
96
  </header>
84
97
 
85
98
  <div class="content">
@@ -129,6 +129,11 @@ kbd {
129
129
  box-shadow: inset 0 -2px 0 var(--kbd-wrap-color);
130
130
  }
131
131
 
132
+ hr {
133
+ border-color: var(--main-border-color);
134
+ opacity: 1;
135
+ }
136
+
132
137
  footer {
133
138
  background-color: var(--main-bg);
134
139
  height: $footer-height;
@@ -364,7 +369,6 @@ main {
364
369
 
365
370
  h1 {
366
371
  margin-top: 2rem;
367
- margin-bottom: 1.5rem;
368
372
  }
369
373
 
370
374
  p {
@@ -550,17 +554,32 @@ main {
550
554
  width: 100%;
551
555
  height: 100%;
552
556
  margin-bottom: 1rem;
557
+ aspect-ratio: 16 / 9;
553
558
 
554
559
  @extend %rounded;
555
560
 
556
- &.youtube,
557
- &.bilibili {
558
- aspect-ratio: 16 / 9;
559
- }
560
-
561
561
  &.twitch {
562
562
  aspect-ratio: 310 / 189;
563
563
  }
564
+
565
+ &.file {
566
+ display: block;
567
+ width: auto;
568
+ height: auto;
569
+ max-width: 100%;
570
+ max-height: 100%;
571
+ margin: auto;
572
+ margin-bottom: 0;
573
+ }
574
+
575
+ @extend %img-caption;
576
+ }
577
+
578
+ .embed-audio {
579
+ width: 100%;
580
+ display: block;
581
+
582
+ @extend %img-caption;
564
583
  }
565
584
 
566
585
  /* --- buttons --- */
@@ -577,26 +596,6 @@ main {
577
596
 
578
597
  /* --- Effects classes --- */
579
598
 
580
- .loaded {
581
- display: block !important;
582
-
583
- @at-root .d-flex#{&} {
584
- display: flex !important;
585
- }
586
- }
587
-
588
- .unloaded {
589
- display: none !important;
590
- }
591
-
592
- .visible {
593
- visibility: visible !important;
594
- }
595
-
596
- .hidden {
597
- visibility: hidden !important;
598
- }
599
-
600
599
  .flex-grow-1 {
601
600
  flex-grow: 1 !important;
602
601
  }
@@ -653,18 +652,6 @@ main {
653
652
 
654
653
  /* --- Overriding --- */
655
654
 
656
- /* magnific-popup */
657
-
658
- figure .mfp-title {
659
- text-align: center;
660
- padding-right: 0;
661
- margin-top: 0.5rem;
662
- }
663
-
664
- .mfp-img {
665
- transition: none;
666
- }
667
-
668
655
  /* mermaid */
669
656
  .mermaid {
670
657
  text-align: center;
@@ -836,7 +823,10 @@ $btn-mb: 0.5rem;
836
823
  display: flex;
837
824
  align-items: center;
838
825
  justify-content: center;
839
- box-shadow: var(--sidebar-border-color) 0 0 0 1px;
826
+
827
+ &:not(:focus-visible) {
828
+ box-shadow: var(--sidebar-border-color) 0 0 0 1px;
829
+ }
840
830
 
841
831
  &:hover {
842
832
  background-color: var(--sidebar-hover-bg);
@@ -857,10 +847,7 @@ $btn-mb: 0.5rem;
857
847
  line-height: $btn-size;
858
848
  }
859
849
 
860
- .mode-toggle {
861
- padding: 0;
862
- border: 0;
863
-
850
+ #mode-toggle {
864
851
  @extend %button;
865
852
  @extend %sidebar-links;
866
853
  @extend %sidebar-link-hover;
@@ -1139,7 +1126,8 @@ search {
1139
1126
  /* --- button back-to-top --- */
1140
1127
 
1141
1128
  #back-to-top {
1142
- display: none;
1129
+ visibility: hidden;
1130
+ opacity: 0;
1143
1131
  z-index: 1;
1144
1132
  cursor: pointer;
1145
1133
  position: fixed;
@@ -1152,8 +1140,7 @@ search {
1152
1140
  height: $back2top-size;
1153
1141
  border-radius: 50%;
1154
1142
  border: 1px solid var(--btn-backtotop-border-color);
1155
- transition: transform 0.2s ease-out;
1156
- -webkit-transition: transform 0.2s ease-out;
1143
+ transition: opacity 0.5s ease-in-out, transform 0.2s ease-out;
1157
1144
 
1158
1145
  &:hover {
1159
1146
  transform: translate3d(0, -5px, 0);
@@ -1165,6 +1152,11 @@ search {
1165
1152
  position: relative;
1166
1153
  bottom: 2px;
1167
1154
  }
1155
+
1156
+ &.show {
1157
+ opacity: 1;
1158
+ visibility: visible;
1159
+ }
1168
1160
  }
1169
1161
 
1170
1162
  #notification {
@@ -104,10 +104,6 @@
104
104
  display: none;
105
105
  }
106
106
 
107
- hr {
108
- border-color: var(--main-border-color);
109
- }
110
-
111
107
  /* categories */
112
108
  .categories.card,
113
109
  .list-group-item {