hexo-theme-gnix 9.0.0 → 10.0.0

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.
Files changed (66) hide show
  1. package/README.md +4 -2
  2. package/include/hexo/feed.js +5 -5
  3. package/include/hexo/filter.js +25 -1
  4. package/include/hexo/generator/archive.js +116 -0
  5. package/include/hexo/generator/home.js +64 -0
  6. package/include/hexo/generator/index.js +82 -0
  7. package/include/hexo/generator/md_generator.js +87 -0
  8. package/include/hexo/generator/page.js +55 -0
  9. package/include/hexo/generator/tag.js +84 -0
  10. package/include/hexo/helper.js +38 -0
  11. package/include/hexo/i18n.js +183 -0
  12. package/include/util/article_font.js +132 -0
  13. package/include/util/i18n.js +280 -0
  14. package/include/util/theme.js +84 -0
  15. package/languages/en.yml +28 -0
  16. package/languages/zh-CN.yml +28 -0
  17. package/layout/archive.jsx +131 -127
  18. package/layout/common/article.jsx +283 -16
  19. package/layout/common/article_info.jsx +339 -0
  20. package/layout/common/article_media.jsx +11 -4
  21. package/layout/common/comment.jsx +15 -7
  22. package/layout/common/footer.jsx +6 -5
  23. package/layout/common/head.jsx +121 -32
  24. package/layout/common/navbar.jsx +195 -65
  25. package/layout/common/theme_selector.jsx +16 -14
  26. package/layout/layout.jsx +43 -5
  27. package/layout/misc/open_graph.jsx +162 -66
  28. package/layout/misc/paginator.jsx +2 -8
  29. package/layout/plugin/cookie_consent.jsx +252 -53
  30. package/layout/plugin/swup.jsx +1 -1
  31. package/layout/search/insight.jsx +1 -1
  32. package/layout/tag.jsx +3 -2
  33. package/layout/tags.jsx +81 -73
  34. package/package.json +5 -5
  35. package/scripts/index.js +1 -0
  36. package/source/css/archive.css +225 -180
  37. package/source/css/default.css +1162 -98
  38. package/source/css/responsive.css +426 -0
  39. package/source/css/shiki/shiki.css +12 -2081
  40. package/source/css/tags.css +183 -0
  41. package/source/css/twikoo.css +1049 -1045
  42. package/source/img/favicon.svg +1 -6
  43. package/source/img/og_image.webp +0 -0
  44. package/source/js/article-font-utils.js +99 -0
  45. package/source/js/busuanzi.js +91 -24
  46. package/source/js/components/chat.js +169 -50
  47. package/source/js/components/image-carousel.js +152 -108
  48. package/source/js/components/sidenote.js +210 -0
  49. package/source/js/components/text-image-section.js +78 -90
  50. package/source/js/components/theme-stacked.js +65 -33
  51. package/source/js/components/tree.js +30 -16
  52. package/source/js/decrypt.js +7 -2
  53. package/source/js/main.js +428 -5
  54. package/source/js/swup.js +39 -0
  55. package/source/js/theme-selector.js +26 -16
  56. package/include/hexo/generator.js +0 -53
  57. package/layout/misc/article_licensing.jsx +0 -99
  58. package/source/css/responsive/desktop.css +0 -36
  59. package/source/css/responsive/mobile.css +0 -29
  60. package/source/css/responsive/tablet.css +0 -43
  61. package/source/css/responsive/touch.css +0 -155
  62. package/source/img/logo.svg +0 -9
  63. package/source/js/archive-breadcrumb.js +0 -132
  64. package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.css +0 -6
  65. package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.js +0 -1
  66. package/source/js/swup.bundle.js +0 -1
@@ -1,7 +1,18 @@
1
1
  const { Component, isValidDate, parseISO } = require("../../include/util/common");
2
- const { encodeURL, stripHTML, escapeHTML } = require("hexo-util");
2
+ const { encodeURL, stripHTML } = require("hexo-util");
3
+
4
+ const DESCRIPTION_LENGTH = 160;
5
+ const IMAGE_TYPES = {
6
+ avif: "image/avif",
7
+ gif: "image/gif",
8
+ jpeg: "image/jpeg",
9
+ jpg: "image/jpeg",
10
+ png: "image/png",
11
+ webp: "image/webp",
12
+ };
3
13
 
4
14
  const localeMap = {
15
+ zh: "zh_CN",
5
16
  en: "en_US",
6
17
  de: "de_DE",
7
18
  es: "es_ES",
@@ -17,91 +28,176 @@ const localeMap = {
17
28
  tr: "tr_TR",
18
29
  vi: "vi_VN",
19
30
  };
20
- const localeRegex = new RegExp(Object.keys(localeMap).join("|"), "i");
31
+
32
+ function normalizeText(value, maxLength) {
33
+ if (typeof value !== "string") return "";
34
+
35
+ const text = stripHTML(value).replace(/\s+/g, " ").trim();
36
+ if (!maxLength || text.length <= maxLength) return text;
37
+
38
+ return (
39
+ text
40
+ .slice(0, maxLength)
41
+ .replace(/\s+\S*$/, "")
42
+ .trim() || text.slice(0, maxLength).trim()
43
+ );
44
+ }
45
+
46
+ function normalizeUrl(value, base) {
47
+ if (!value) return "";
48
+
49
+ try {
50
+ return encodeURL(new URL(value, base).toString());
51
+ } catch (_) {
52
+ return "";
53
+ }
54
+ }
55
+
56
+ function normalizeLocale(language) {
57
+ if (typeof language !== "string") return "";
58
+
59
+ const normalized = language.replace("_", "-").trim();
60
+ if (normalized.length === 2) {
61
+ return localeMap[normalized.toLowerCase()] || "";
62
+ }
63
+
64
+ if (/^[a-z]{2}-[a-z]{2}$/i.test(normalized)) {
65
+ const [lang, territory] = normalized.split("-");
66
+ return `${lang.toLowerCase()}_${territory.toUpperCase()}`;
67
+ }
68
+
69
+ return "";
70
+ }
71
+
72
+ function normalizeImageUrls(images, base) {
73
+ const values = Array.isArray(images) ? images : [images];
74
+
75
+ return [
76
+ ...new Set(
77
+ values
78
+ .filter(Boolean)
79
+ .map((path) => normalizeUrl(path, base))
80
+ .filter(Boolean)
81
+ .filter((url) => {
82
+ try {
83
+ const { protocol } = new URL(url);
84
+ return protocol === "http:" || protocol === "https:";
85
+ } catch (_) {
86
+ return false;
87
+ }
88
+ }),
89
+ ),
90
+ ];
91
+ }
92
+
93
+ function getImageType(url) {
94
+ try {
95
+ const ext = new URL(url).pathname.split(".").pop().toLowerCase();
96
+ return IMAGE_TYPES[ext] || "";
97
+ } catch (_) {
98
+ return "";
99
+ }
100
+ }
101
+
102
+ function normalizeKeywords(keywords) {
103
+ const values = Array.isArray(keywords) ? keywords : [keywords];
104
+ const names = values.flatMap((keyword) => {
105
+ const value = keyword && typeof keyword === "object" ? keyword.name : keyword;
106
+ if (typeof value !== "string") return [];
107
+ return value.split(",");
108
+ });
109
+
110
+ return [...new Set(names.map((keyword) => normalizeText(keyword)).filter(Boolean))];
111
+ }
112
+
113
+ function normalizeTwitterHandle(value) {
114
+ const handle = normalizeText(value);
115
+ if (!handle) return "";
116
+
117
+ return handle.startsWith("@") ? handle : `@${handle}`;
118
+ }
119
+
120
+ function normalizeDate(value) {
121
+ if (!value) return "";
122
+
123
+ const date = typeof value === "string" ? parseISO(value) : value;
124
+ return isValidDate(date) ? date.toISOString() : "";
125
+ }
21
126
 
22
127
  module.exports = class extends Component {
23
128
  render() {
24
- const { type, title, date, updated, author, url, siteName, twitterCard, twitterSite, googlePlus, facebookAdmins, facebookAppId } = this.props;
25
- let { description, language, images, keywords, twitterId } = this.props;
129
+ const { type, title, date, updated, author, url, siteName, twitterCard, twitterSite, googlePlus, facebookAdmins, facebookAppId, section, imageWidth, imageHeight } = this.props;
26
130
 
27
- const htmlTags = [];
131
+ let { description, language, images, keywords, twitterId, imageAlt } = this.props;
28
132
 
133
+ const htmlTags = [];
134
+ const ogType = type || "website";
135
+ const isArticle = ogType === "article";
136
+ const pageUrl = normalizeUrl(url, url);
137
+ const normalizedTitle = normalizeText(title || siteName);
138
+ const normalizedSiteName = normalizeText(siteName);
139
+ const normalizedAuthor = normalizeText(author);
140
+ const publishedTime = normalizeDate(date);
141
+ const modifiedTime = normalizeDate(updated);
142
+ const normalizedKeywords = normalizeKeywords(keywords);
143
+
144
+ description = normalizeText(description, DESCRIPTION_LENGTH);
29
145
  if (description) {
30
- description = escapeHTML(stripHTML(description).substring(0, 200).trim()).replace(/\n/g, " ");
31
146
  htmlTags.push(<meta name="description" content={description} />);
32
147
  htmlTags.push(<meta property="og:description" content={description} />);
33
148
  }
34
149
 
35
- htmlTags.push(<meta property="og:type" content={type || "website"} />);
36
- htmlTags.push(<meta property="og:title" content={title} />);
37
- htmlTags.push(<meta property="og:url" content={encodeURL(url)} />);
38
- htmlTags.push(<meta property="og:site_name" content={siteName} />);
39
-
40
- if (language) {
41
- if (language.length === 2) {
42
- language = language.replace(localeRegex, (str) => localeMap[str]);
43
- htmlTags.push(<meta property="og:locale" content={language} />);
44
- } else if (language.length === 5) {
45
- const territory = language.slice(-2);
46
- const territoryRegex = new RegExp(territory.concat("$"));
47
- language = language.replace("-", "_").replace(territoryRegex, territory.toUpperCase());
48
- htmlTags.push(<meta property="og:locale" content={language} />);
49
- }
50
- }
51
-
52
- if (!Array.isArray(images)) {
53
- images = [images];
54
- }
55
- images
56
- .map((path) => {
57
- const parsed = new URL(path, url);
58
- return parsed.toString();
59
- })
60
- .forEach((path) => {
61
- htmlTags.push(<meta property="og:image" content={path} />);
62
- });
63
-
64
- if (date) {
65
- const d = typeof date === "string" ? parseISO(date) : date;
66
- if (isValidDate(d)) {
67
- htmlTags.push(<meta property="article:published_time" content={d.toISOString()} />);
68
- }
69
- }
150
+ htmlTags.push(<meta property="og:type" content={ogType} />);
151
+ if (normalizedTitle) htmlTags.push(<meta property="og:title" content={normalizedTitle} />);
152
+ if (pageUrl) htmlTags.push(<meta property="og:url" content={pageUrl} />);
153
+ if (normalizedSiteName) htmlTags.push(<meta property="og:site_name" content={normalizedSiteName} />);
70
154
 
71
- if (updated) {
72
- const u = typeof updated === "string" ? parseISO(updated) : updated;
73
- if (isValidDate(u)) {
74
- htmlTags.push(<meta property="article:modified_time" content={u.toISOString()} />);
75
- }
76
- }
155
+ language = normalizeLocale(language);
156
+ if (language) htmlTags.push(<meta property="og:locale" content={language} />);
77
157
 
78
- if (author) htmlTags.push(<meta property="article:author" content={author} />);
158
+ const imageUrls = normalizeImageUrls(images, pageUrl || url);
159
+ imageAlt = normalizeText(imageAlt || title);
79
160
 
80
- if (keywords) {
81
- if (typeof keywords === "string") {
82
- keywords = [keywords];
83
- }
161
+ imageUrls.forEach((path) => {
162
+ htmlTags.push(<meta property="og:image" content={path} />);
163
+ if (path.startsWith("https://")) htmlTags.push(<meta property="og:image:secure_url" content={path} />);
84
164
 
85
- keywords
86
- .map((tag) => {
87
- return tag.name ? tag.name : tag;
88
- })
89
- .filter(Boolean)
90
- .forEach((keyword) => {
91
- htmlTags.push(<meta property="article:tag" content={keyword} />);
92
- });
93
- }
165
+ const imageType = getImageType(path);
166
+ if (imageType) htmlTags.push(<meta property="og:image:type" content={imageType} />);
167
+ if (imageWidth) htmlTags.push(<meta property="og:image:width" content={imageWidth} />);
168
+ if (imageHeight) htmlTags.push(<meta property="og:image:height" content={imageHeight} />);
169
+ if (imageAlt) htmlTags.push(<meta property="og:image:alt" content={imageAlt} />);
170
+ });
94
171
 
95
- htmlTags.push(<meta property="twitter:card" content={twitterCard || "summary"} />);
172
+ if (isArticle) {
173
+ if (publishedTime) htmlTags.push(<meta property="article:published_time" content={publishedTime} />);
174
+ if (modifiedTime) htmlTags.push(<meta property="article:modified_time" content={modifiedTime} />);
175
+ if (normalizedAuthor) htmlTags.push(<meta property="article:author" content={normalizedAuthor} />);
96
176
 
97
- if (twitterId) htmlTags.push(<meta property="twitter:creator" content={twitterId} />);
177
+ const normalizedSection = normalizeText(section);
178
+ if (normalizedSection) htmlTags.push(<meta property="article:section" content={normalizedSection} />);
98
179
 
99
- if (twitterSite) htmlTags.push(<meta property="twitter:site" content={twitterSite} />);
180
+ normalizedKeywords.forEach((keyword) => {
181
+ htmlTags.push(<meta property="article:tag" content={keyword} />);
182
+ });
183
+ } else if (modifiedTime) {
184
+ htmlTags.push(<meta property="og:updated_time" content={modifiedTime} />);
185
+ }
100
186
 
187
+ htmlTags.push(<meta name="twitter:card" content={twitterCard || (imageUrls.length > 0 ? "summary_large_image" : "summary")} />);
188
+ if (normalizedTitle) htmlTags.push(<meta name="twitter:title" content={normalizedTitle} />);
189
+ if (description) htmlTags.push(<meta name="twitter:description" content={description} />);
190
+ if (pageUrl) htmlTags.push(<meta name="twitter:url" content={pageUrl} />);
191
+ if (imageUrls.length > 0) {
192
+ htmlTags.push(<meta name="twitter:image" content={imageUrls[0]} />);
193
+ if (imageAlt) htmlTags.push(<meta name="twitter:image:alt" content={imageAlt} />);
194
+ }
195
+ const normalizedTwitterId = normalizeTwitterHandle(twitterId);
196
+ const normalizedTwitterSite = normalizeTwitterHandle(twitterSite);
197
+ if (normalizedTwitterId) htmlTags.push(<meta name="twitter:creator" content={normalizedTwitterId} />);
198
+ if (normalizedTwitterSite) htmlTags.push(<meta name="twitter:site" content={normalizedTwitterSite} />);
101
199
  if (googlePlus) htmlTags.push(<link rel="publisher" href={googlePlus} />);
102
-
103
200
  if (facebookAdmins) htmlTags.push(<meta property="fb:admins" content={facebookAdmins} />);
104
-
105
201
  if (facebookAppId) htmlTags.push(<meta property="fb:app_id" content={facebookAppId} />);
106
202
 
107
203
  return <>{htmlTags}</>;
@@ -57,16 +57,10 @@ module.exports = class extends Component {
57
57
  return (
58
58
  <nav class="pagination card" aria-label="pagination">
59
59
  <a href={getPageUrl(current - 1)} class={`pagination-previous`} style={current > 1 ? {} : { visibility: "hidden" }}>
60
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
61
- <title>go to previous page</title>
62
- <path fill="currentColor" d="m4 10l9 9l1.4-1.5L7 10l7.4-7.5L13 1z" />
63
- </svg>
60
+ Prev
64
61
  </a>
65
62
  <a href={getPageUrl(current + 1)} class={`pagination-next`} style={current < total ? {} : { visibility: "hidden" }}>
66
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
67
- <title>go to next page</title>
68
- <path fill="currentColor" d="M7 1L5.6 2.5L13 10l-7.4 7.5L7 19l9-9z" />
69
- </svg>
63
+ Next
70
64
  </a>
71
65
  <ul class="pagination-list is-hidden-mobile">{pagination(current, total)}</ul>
72
66
  </nav>
@@ -1,51 +1,264 @@
1
1
  const { Component, cacheComponent } = require("../../include/util/common");
2
2
 
3
+ const STORAGE_KEY = "gnix:cookie-consent";
4
+ const LEGACY_STORAGE_KEY = "cookieconsent_status";
5
+
6
+ const COOKIE_CONSENT_STYLE = `
7
+ .gnix-cookie-consent {
8
+ --cookie-consent-x: 0;
9
+ --cookie-consent-y: 0.5rem;
10
+ position: fixed;
11
+ bottom: max(1rem, env(safe-area-inset-bottom));
12
+ left: max(1rem, env(safe-area-inset-left));
13
+ z-index: 140;
14
+ box-sizing: border-box;
15
+ display: grid;
16
+ grid-template-columns: minmax(0, 1fr) auto;
17
+ gap: 0.875rem 1rem;
18
+ width: min(32rem, calc(100vw - 2rem));
19
+ padding: 1rem;
20
+ border: 1px solid var(--surface0);
21
+ border-radius: var(--radius);
22
+ background: var(--mantle);
23
+ color: var(--text);
24
+ box-shadow:
25
+ 0 20px 60px -32px rgba(0, 0, 0, 0.58),
26
+ 0 0 0 1px hsl(from var(--base) h s l / 0.18);
27
+ font-family: var(--font-sans-serif);
28
+ line-height: 1.55;
29
+ opacity: 0;
30
+ transform: translate3d(var(--cookie-consent-x), var(--cookie-consent-y), 0);
31
+ transition:
32
+ opacity 0.18s ease,
33
+ transform 0.18s ease;
34
+ }
35
+
36
+ @supports (background: color-mix(in oklch, black 50%, transparent)) {
37
+ .gnix-cookie-consent {
38
+ background: color-mix(in oklch, var(--mantle) 88%, transparent);
39
+ -webkit-backdrop-filter: blur(16px) saturate(1.2);
40
+ backdrop-filter: blur(16px) saturate(1.2);
41
+ }
42
+ }
43
+
44
+ .gnix-cookie-consent.is-visible {
45
+ --cookie-consent-y: 0;
46
+ opacity: 1;
47
+ }
48
+
49
+ .gnix-cookie-consent.is-hiding {
50
+ --cookie-consent-y: 0.5rem;
51
+ opacity: 0;
52
+ pointer-events: none;
53
+ }
54
+
55
+ .gnix-cookie-consent.is-static {
56
+ position: static;
57
+ width: min(42rem, calc(100% - 2rem));
58
+ margin: 1rem auto;
59
+ }
60
+
61
+ .gnix-cookie-consent__message {
62
+ min-width: 0;
63
+ margin: 0;
64
+ color: var(--subtext1);
65
+ font-size: 0.9rem;
66
+ }
67
+
68
+ .gnix-cookie-consent__link {
69
+ color: var(--lavender);
70
+ text-decoration: none;
71
+ white-space: nowrap;
72
+ }
73
+
74
+ .gnix-cookie-consent__link:hover {
75
+ text-decoration: underline;
76
+ }
77
+
78
+ .gnix-cookie-consent__actions {
79
+ display: flex;
80
+ flex-wrap: wrap;
81
+ align-items: center;
82
+ justify-content: flex-end;
83
+ gap: 0.5rem;
84
+ }
85
+
86
+ .gnix-cookie-consent__button {
87
+ min-height: 2.25rem;
88
+ padding: 0.55rem 0.8rem;
89
+ border: 1px solid var(--surface0);
90
+ border-radius: 8px;
91
+ background: hsl(from var(--surface0) h s l / 0.24);
92
+ color: var(--text);
93
+ cursor: pointer;
94
+ font: 600 0.78rem/1 var(--font-sans-serif);
95
+ transition:
96
+ background-color 0.15s ease,
97
+ border-color 0.15s ease,
98
+ color 0.15s ease,
99
+ transform 0.15s ease;
100
+ }
101
+
102
+ .gnix-cookie-consent__button:hover {
103
+ border-color: var(--overlay0);
104
+ background: hsl(from var(--surface0) h s l / 0.38);
105
+ transform: translateY(-1px);
106
+ }
107
+
108
+ .gnix-cookie-consent__button:focus-visible {
109
+ outline: 2px solid var(--lavender);
110
+ outline-offset: 2px;
111
+ }
112
+
113
+ .gnix-cookie-consent__button--primary {
114
+ border-color: var(--lavender);
115
+ background: var(--lavender);
116
+ color: var(--base);
117
+ }
118
+
119
+ .gnix-cookie-consent__button--primary:hover {
120
+ border-color: var(--mauve);
121
+ background: var(--mauve);
122
+ color: var(--base);
123
+ }
124
+
125
+ @media (max-width: 640px) {
126
+ .gnix-cookie-consent {
127
+ left: max(0.75rem, env(safe-area-inset-left));
128
+ grid-template-columns: 1fr;
129
+ width: auto;
130
+ padding: 0.875rem;
131
+ --cookie-consent-x: 0;
132
+ }
133
+
134
+ .gnix-cookie-consent__actions {
135
+ justify-content: stretch;
136
+ }
137
+
138
+ .gnix-cookie-consent__button {
139
+ flex: 1 1 auto;
140
+ }
141
+ }
142
+ `;
143
+
144
+ function stringifyScriptData(value) {
145
+ return JSON.stringify(value).replace(/</g, "\\u003c");
146
+ }
147
+
3
148
  class CookieConsent extends Component {
4
- // https://www.osano.com/cookieconsent/documentation/javascript-api/
5
149
  render() {
6
- const { head, text, jsUrl, cssUrl } = this.props;
7
- const { type, theme, position, policyLink } = this.props;
8
- const { message, dismiss, allow, deny, link, policy } = text;
150
+ const { head } = this.props;
9
151
 
10
152
  if (head) {
11
- return <link rel="preload" href={cssUrl} as="style" onload="this.onload=null;this.rel='stylesheet'" />;
153
+ return <style id="gnix-cookie-consent-style" dangerouslySetInnerHTML={{ __html: COOKIE_CONSENT_STYLE }} />;
12
154
  }
155
+
156
+ const options = {
157
+ storageKey: STORAGE_KEY,
158
+ legacyStorageKey: LEGACY_STORAGE_KEY,
159
+ policyLink: this.props.policyLink,
160
+ isStatic: this.props.isStatic,
161
+ };
162
+
13
163
  return (
14
164
  <script
15
165
  dangerouslySetInnerHTML={{
16
166
  __html: `
17
167
  (function() {
18
- var s = document.createElement('script');
19
- s.src = ${JSON.stringify(jsUrl)};
20
- s.defer = true;
21
- s.onload = function() {
22
- window.cookieconsent.initialise(${JSON.stringify({
23
- type,
24
- theme,
25
- static: this.props.static,
26
- position,
27
- content: {
28
- message,
29
- dismiss,
30
- allow,
31
- deny,
32
- link,
33
- policy,
34
- href: policyLink,
35
- },
36
- palette: {
37
- popup: {
38
- background: "var(--base)",
39
- text: "var(--text)",
40
- },
41
- button: {
42
- background: "var(--lavender)",
43
- text: "var(--base)",
44
- },
45
- },
46
- })});
47
- };
48
- document.body.appendChild(s);
168
+ var options = ${stringifyScriptData(options)};
169
+ var rootSelector = "[data-gnix-cookie-consent]";
170
+
171
+ function readStoredConsent() {
172
+ try {
173
+ var stored = window.localStorage && (localStorage.getItem(options.storageKey) || localStorage.getItem(options.legacyStorageKey));
174
+ if (stored) return stored;
175
+ } catch (_) {}
176
+
177
+ var match = document.cookie.match(/(?:^|; )cookieconsent_status=([^;]+)/);
178
+ return match ? decodeURIComponent(match[1]) : "";
179
+ }
180
+
181
+ function writeConsent(status) {
182
+ try {
183
+ localStorage.setItem(options.storageKey, status);
184
+ localStorage.setItem(options.legacyStorageKey, status);
185
+ } catch (_) {}
186
+
187
+ document.cookie = "cookieconsent_status=" + encodeURIComponent(status) + "; path=/; max-age=31536000; SameSite=Lax";
188
+ window.gnixCookieConsent = { status: status };
189
+
190
+ try {
191
+ window.dispatchEvent(new CustomEvent("gnix:cookie-consent", { detail: { status: status } }));
192
+ } catch (_) {}
193
+ }
194
+
195
+ function createButton(label, action, variant) {
196
+ var button = document.createElement("button");
197
+ button.type = "button";
198
+ button.className = "gnix-cookie-consent__button" + (variant ? " gnix-cookie-consent__button--" + variant : "");
199
+ button.textContent = label;
200
+ button.setAttribute("data-cookie-consent-action", action);
201
+ return button;
202
+ }
203
+
204
+ function closeConsent(root, status) {
205
+ writeConsent(status);
206
+ root.classList.remove("is-visible");
207
+ root.classList.add("is-hiding");
208
+ window.setTimeout(function() {
209
+ if (root.parentNode) root.parentNode.removeChild(root);
210
+ }, 180);
211
+ }
212
+
213
+ function initCookieConsent() {
214
+ if (readStoredConsent() || document.querySelector(rootSelector)) return;
215
+
216
+ var root = document.createElement("aside");
217
+ root.className = "gnix-cookie-consent" + (options.isStatic ? " is-static" : "");
218
+ root.setAttribute("data-gnix-cookie-consent", "");
219
+ root.setAttribute("role", "dialog");
220
+ root.setAttribute("aria-live", "polite");
221
+ root.setAttribute("aria-label", "Cookie notice");
222
+
223
+ var message = document.createElement("p");
224
+ message.className = "gnix-cookie-consent__message";
225
+ message.appendChild(document.createTextNode("This website uses cookies to improve your experience."));
226
+
227
+ if (options.policyLink) {
228
+ var link = document.createElement("a");
229
+ link.className = "gnix-cookie-consent__link";
230
+ link.href = options.policyLink;
231
+ link.target = "_blank";
232
+ link.rel = "noopener";
233
+ link.textContent = "Learn more";
234
+ message.appendChild(document.createTextNode(" "));
235
+ message.appendChild(link);
236
+ }
237
+
238
+ var actions = document.createElement("div");
239
+ actions.className = "gnix-cookie-consent__actions";
240
+ actions.appendChild(createButton("Decline", "deny"));
241
+ actions.appendChild(createButton("Accept", "allow", "primary"));
242
+
243
+ actions.addEventListener("click", function(event) {
244
+ var button = event.target.closest("[data-cookie-consent-action]");
245
+ if (!button) return;
246
+ closeConsent(root, button.getAttribute("data-cookie-consent-action"));
247
+ });
248
+
249
+ root.appendChild(message);
250
+ root.appendChild(actions);
251
+ document.body.appendChild(root);
252
+ window.requestAnimationFrame(function() {
253
+ root.classList.add("is-visible");
254
+ });
255
+ }
256
+
257
+ if (document.readyState === "loading") {
258
+ document.addEventListener("DOMContentLoaded", initCookieConsent, { once: true });
259
+ } else {
260
+ initCookieConsent();
261
+ }
49
262
  })();
50
263
  `,
51
264
  }}
@@ -55,26 +268,12 @@ class CookieConsent extends Component {
55
268
  }
56
269
 
57
270
  CookieConsent.Cacheable = cacheComponent(CookieConsent, "plugin.cookieconsent", (props) => {
58
- const { head, plugin, helper } = props;
59
- const { type = "info", theme = "edgeless", position = "bottom-left", policyLink = "https://www.cookiesandyou.com/" } = plugin;
271
+ const { head, plugin } = props;
60
272
 
61
273
  return {
62
274
  head,
63
- type,
64
- theme,
65
- position,
66
- policyLink,
67
- static: plugin.static || false,
68
- text: {
69
- message: helper.__("plugin.cookie_consent.message"),
70
- dismiss: helper.__("plugin.cookie_consent.dismiss"),
71
- allow: helper.__("plugin.cookie_consent.allow"),
72
- deny: helper.__("plugin.cookie_consent.deny"),
73
- link: helper.__("plugin.cookie_consent.link"),
74
- policy: helper.__("plugin.cookie_consent.policy"),
75
- },
76
- cssUrl: helper.cdn("cookieconsent", "3.1.1", "build/cookieconsent.min.css"),
77
- jsUrl: helper.cdn("cookieconsent", "3.1.1", "build/cookieconsent.min.js"),
275
+ policyLink: plugin.policyLink || "https://www.cookiesandyou.com/",
276
+ isStatic: plugin.static || false,
78
277
  };
79
278
  });
80
279
 
@@ -6,7 +6,7 @@ class Swup extends Component {
6
6
  return null;
7
7
  }
8
8
 
9
- return <script defer src="/js/swup.bundle.js"></script>;
9
+ return <script type="module" data-swup-ignore-script src="/js/swup.js"></script>;
10
10
  }
11
11
  }
12
12
 
@@ -52,7 +52,7 @@ Insight.Cacheable = cacheComponent(Insight, "search.insight", (props) => {
52
52
  pages: helper._p("common.page", Infinity),
53
53
  tags: helper._p("common.tag", Infinity),
54
54
  },
55
- contentUrl: helper.url_for("/content.json"),
55
+ contentUrl: helper.is_i18n_enabled() ? helper.localized_url_for("/content.json") : helper.url_for("/content.json"),
56
56
  jsUrl: helper.url_for("/js/insight.js"),
57
57
  };
58
58
  });
package/layout/tag.jsx CHANGED
@@ -48,7 +48,8 @@ const breadcrumb_css = `
48
48
  module.exports = class extends Component {
49
49
  render() {
50
50
  const { config, page, helper } = this.props;
51
- const { url_for, _p } = helper;
51
+ const { _p } = helper;
52
+ const langKey = helper.language_key(page);
52
53
 
53
54
  return (
54
55
  <Fragment>
@@ -57,7 +58,7 @@ module.exports = class extends Component {
57
58
  <ul>
58
59
  <li>
59
60
  <font style="color: var(--green)">$</font>&nbsp;ls&nbsp;
60
- <a href={url_for("/tags/")}>{_p("common.tag", Infinity)}/</a>
61
+ <a href={helper.localized_url_for("/tags/", langKey)}>{_p("common.tag", Infinity)}/</a>
61
62
  </li>
62
63
  <li>
63
64
  <a href="#" aria-current="page" style="cursor: default; pointer-events: none; color: var(--mauve);">