From 5c4d02c89eddefa8089bb4fa5940351d43fbf4d4 Mon Sep 17 00:00:00 2001 From: neveler <55753029+neveler@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:13:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AE=BE=E7=BD=AE=E9=A1=B5?= =?UTF-8?q?=20(#362)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _config.yml | 3 +- _data/navigation.yml | 2 + _data/settings.yaml | 35 ++++++++++ _includes/head/custom.html | 1 + _layouts/settings.html | 46 +++++++++++++ _sass/minimal-mistakes-plus.scss | 40 ++++++----- assets/css/main.scss | 16 ++--- assets/css/skins/air.scss | 8 +++ assets/css/skins/aqua.scss | 8 +++ assets/css/skins/contrast.scss | 8 +++ assets/css/{ => skins}/dark.scss | 16 ++--- assets/css/skins/default.scss | 2 + assets/css/skins/dirt.scss | 8 +++ assets/css/skins/mint.scss | 8 +++ assets/css/skins/neon.scss | 8 +++ assets/css/skins/plum.scss | 8 +++ assets/css/skins/sunrise.scss | 8 +++ assets/js/settings.js | 76 ++++++++++++++++++++ assets/js/theme.js | 115 +++++++++++++++++++------------ settings.yaml | 43 ++++++++++++ 20 files changed, 380 insertions(+), 79 deletions(-) create mode 100644 _data/settings.yaml create mode 100644 _layouts/settings.html create mode 100644 assets/css/skins/air.scss create mode 100644 assets/css/skins/aqua.scss create mode 100644 assets/css/skins/contrast.scss rename assets/css/{ => skins}/dark.scss (68%) create mode 100644 assets/css/skins/default.scss create mode 100644 assets/css/skins/dirt.scss create mode 100644 assets/css/skins/mint.scss create mode 100644 assets/css/skins/neon.scss create mode 100644 assets/css/skins/plum.scss create mode 100644 assets/css/skins/sunrise.scss create mode 100644 assets/js/settings.js create mode 100644 settings.yaml diff --git a/_config.yml b/_config.yml index 5b074d3..1cce97c 100644 --- a/_config.yml +++ b/_config.yml @@ -139,8 +139,6 @@ defaults: # Theme Settings theme: minimal-mistakes-jekyll -minimal_mistakes_skin: default # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise" -minimal_mistakes_skin_dark: dark # Site Settings locale: zh @@ -309,6 +307,7 @@ compress_html: envs: development head_scripts: + - /assets/js/settings.js - /assets/js/theme.js after_footer_scripts: - /assets/js/plugins/jquery.auto-redirect.js diff --git a/_data/navigation.yml b/_data/navigation.yml index 40fe95c..563031e 100644 --- a/_data/navigation.yml +++ b/_data/navigation.yml @@ -1,6 +1,8 @@ main: - title: 常见问题 url: /faq.html + - title: 设置 + url: /settings.html docs: - title: 问题集合 diff --git a/_data/settings.yaml b/_data/settings.yaml new file mode 100644 index 0000000..e91dd2c --- /dev/null +++ b/_data/settings.yaml @@ -0,0 +1,35 @@ +appearance_color: + type: radio + default: light + options: + - light + - dark + - auto +appearance_skin_light: + type: radio + default: default + options: + - default + - air + - aqua + - contrast + - dark + - dirt + - neon + - mint + - plum + - sunrise +appearance_skin_dark: + type: radio + default: dark + options: + - default + - air + - aqua + - contrast + - dark + - dirt + - neon + - mint + - plum + - sunrise diff --git a/_includes/head/custom.html b/_includes/head/custom.html index 9f365f2..55de750 100644 --- a/_includes/head/custom.html +++ b/_includes/head/custom.html @@ -1 +1,2 @@ + diff --git a/_layouts/settings.html b/_layouts/settings.html new file mode 100644 index 0000000..af675a0 --- /dev/null +++ b/_layouts/settings.html @@ -0,0 +1,46 @@ +--- +layout: document +--- + +{% for group in page.data %} + +{% capture notice %} + +## {{ group.title }} + +{% for pair in group.settings %} +{% assign name = pair[0] %} +{% assign value = pair[1] %} +{% assign setting = site.data.settings[name] %} + +{% if setting.type == 'radio' %} +
+ +
+ + +{% endif %} +{% endfor %} +{% endcapture %} +{{ notice | markdownify }} +{% endfor %} diff --git a/_sass/minimal-mistakes-plus.scss b/_sass/minimal-mistakes-plus.scss index f0eaae1..1d6d0b4 100644 --- a/_sass/minimal-mistakes-plus.scss +++ b/_sass/minimal-mistakes-plus.scss @@ -1,16 +1,24 @@ -@import "minimal-mistakes"; - -blockquote { - margin-inline: 0; - font-style: normal; -} - -a, span, code, kbd, pre, em, strong, b, i { - overflow-wrap: break-word; - word-wrap: break-word; - word-break: break-word; -} - -.m0 { - margin: 0 !important; -} +@import "minimal-mistakes"; + +blockquote { + margin-inline: 0; + font-style: normal; +} + +* { + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-word; +} + +.notice ul:first-child { + margin-top: 0; +} + +.task-list-item label { + display: inline +} + +.m0 { + margin: 0 !important; +} diff --git a/assets/css/main.scss b/assets/css/main.scss index cd37abb..0f4452f 100644 --- a/assets/css/main.scss +++ b/assets/css/main.scss @@ -1,8 +1,8 @@ ---- ---- - -@charset "utf-8"; - -$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; -@import "minimal-mistakes/skins/{{ site.minimal_mistakes_skin | default: 'default' }}"; -@import "minimal-mistakes-plus"; +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/default"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/air.scss b/assets/css/skins/air.scss new file mode 100644 index 0000000..581fb34 --- /dev/null +++ b/assets/css/skins/air.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/air"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/aqua.scss b/assets/css/skins/aqua.scss new file mode 100644 index 0000000..2a03a4d --- /dev/null +++ b/assets/css/skins/aqua.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/aqua"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/contrast.scss b/assets/css/skins/contrast.scss new file mode 100644 index 0000000..474cc29 --- /dev/null +++ b/assets/css/skins/contrast.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/contrast"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/dark.scss b/assets/css/skins/dark.scss similarity index 68% rename from assets/css/dark.scss rename to assets/css/skins/dark.scss index 8ad895b..b7bb9c2 100644 --- a/assets/css/dark.scss +++ b/assets/css/skins/dark.scss @@ -1,8 +1,8 @@ ---- ---- - -@charset "utf-8"; - -$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; -@import "minimal-mistakes/skins/{{ site.minimal_mistakes_skin_dark | default: 'dark' }}"; -@import "minimal-mistakes-plus"; +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/dark"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/default.scss b/assets/css/skins/default.scss new file mode 100644 index 0000000..a845151 --- /dev/null +++ b/assets/css/skins/default.scss @@ -0,0 +1,2 @@ +--- +--- diff --git a/assets/css/skins/dirt.scss b/assets/css/skins/dirt.scss new file mode 100644 index 0000000..1b711f5 --- /dev/null +++ b/assets/css/skins/dirt.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/dirt"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/mint.scss b/assets/css/skins/mint.scss new file mode 100644 index 0000000..7385126 --- /dev/null +++ b/assets/css/skins/mint.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/mint"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/neon.scss b/assets/css/skins/neon.scss new file mode 100644 index 0000000..4ba4097 --- /dev/null +++ b/assets/css/skins/neon.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/neon"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/plum.scss b/assets/css/skins/plum.scss new file mode 100644 index 0000000..b40391c --- /dev/null +++ b/assets/css/skins/plum.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/plum"; +@import "minimal-mistakes-plus"; diff --git a/assets/css/skins/sunrise.scss b/assets/css/skins/sunrise.scss new file mode 100644 index 0000000..9c33069 --- /dev/null +++ b/assets/css/skins/sunrise.scss @@ -0,0 +1,8 @@ +--- +--- + +@charset "utf-8"; + +$sans-serif: -apple-system, BlinkMacSystemFont, "Roboto", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; +@import "minimal-mistakes/skins/sunrise"; +@import "minimal-mistakes-plus"; diff --git a/assets/js/settings.js b/assets/js/settings.js new file mode 100644 index 0000000..13e6e59 --- /dev/null +++ b/assets/js/settings.js @@ -0,0 +1,76 @@ +--- +layout: null +--- +(function (global) { + var PREFIX = "HMCL_DOCS_SETTINGS_"; + var data = {}; + var events = {}; + var config = /*{%comment%}*/{}/*{%endcomment%}*//**{{'/'}}{{ site.data.settings | jsonify }}/**/; + + global.addEventListener("storage", function (event) { + if (!event.key) return; + if (event.key.indexOf(PREFIX) !== 0) return; + + var handlers = events[event.key]; + if (!handlers) return; + + var newValue = event.newValue; + var oldValue = event.oldValue; + if (oldValue === newValue) return; + + data[event.key] = newValue; + for (var i = 0; i < handlers.length; i++) { + if (typeof handlers[i] === "function") { + handlers[i](newValue, oldValue); + } + } + }); + + var settings = { + set: function (key, value) { + if (config[key] === undefined) return; + var strKey = (PREFIX + key).toUpperCase(); + var newValue = value + ""; + data[strKey] = newValue; + localStorage.setItem(strKey, newValue); + var handlers = events[strKey]; + if (!handlers) return; + + for (var i = 0; i < handlers.length; i++) { + if (typeof handlers[i] === "function") { + handlers[i](newValue); + } + } + }, + + get: function (key, defaultValue) { + if (config[key] === undefined) return; + var strKey = (PREFIX + key).toUpperCase(); + data.hasOwnProperty(strKey) || (data[strKey] = localStorage.getItem(strKey)); + if (typeof defaultValue === "string" && data[strKey] === null) { + return defaultValue; + } + return data[strKey]; + }, + + refresh: function (key) { + if (config[key] === undefined) return; + settings.set(key, settings.get(key, config[key].default)); + }, + + onChange: function (key, handler) { + if (config[key] === undefined) return; + if (typeof handler !== "function") return; + var strKey = (PREFIX + key).toUpperCase(); + if (config[key].type === "radio") { + handler(settings.get(key, config[key].default)); + } + if (!events[strKey]) { + events[strKey] = [handler]; + } else { + events[strKey].push(handler); + } + } + }; + global.settings = settings; +})(window); diff --git a/assets/js/theme.js b/assets/js/theme.js index 9782247..9a20279 100644 --- a/assets/js/theme.js +++ b/assets/js/theme.js @@ -1,45 +1,70 @@ ---- -layout: null ---- -var darkTheme = document.createElement("link"); -darkTheme.rel = "stylesheet alternate"; -darkTheme.href = "{{ '/assets/css/dark.css' | relative_url }}"; -document.head.appendChild(darkTheme); -window.addEventListener("DOMContentLoaded", function () { - var list = document.querySelector(".masthead .visible-links"); - if (!list) return; - var mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); - function handler() { - darkTheme.rel = mediaQuery.matches ? "stylesheet" : "stylesheet alternate"; - } - var current = 0; - var modes = ["light", "dark", "auto"]; - var modeNames = ["亮色", "暗色", "自动"]; - var switcher = document.createElement("a"); - switcher.className = "masthead__menu-item"; - switcher.innerText = modeNames[current]; - switcher.href = "javascript:;"; - switcher.onclick = function () { - themeApply(current + 1); - } - list.appendChild(switcher); - function themeApply(index) { - index = (Number(index) || 0) % modes.length; - if (index === current) return; - if (modes[current] === "auto") mediaQuery.removeEventListener("change", handler); - current = index; - var mode = modes[current]; - switcher.innerText = modeNames[current]; - localStorage.setItem("theme", current); - if (mode === "light") darkTheme.rel = "stylesheet alternate"; - else if (mode === "dark") darkTheme.rel = "stylesheet"; - else { - mediaQuery.addEventListener("change", handler); - handler(); - } - } - themeApply(localStorage.getItem("theme")); - window.addEventListener("storage", function (event) { - event.key === "theme" && themeApply(event.newValue); - }); -}); \ No newline at end of file +--- +layout: null +--- +window.addEventListener("DOMContentLoaded", function () { + var skinLink = document.getElementById("skin"); + var darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)"); + function applyDarkSkin() { + skinLink.href = "{{ '/assets/css/skins/' | relative_url }}" + settings.get("appearance_skin_dark", "dark") + ".css"; + } + function applyLightSkin() { + skinLink.href = "{{ '/assets/css/skins/' | relative_url }}" + settings.get("appearance_skin_light", "default") + ".css"; + } + function autoSchemeHandler() { + if (darkModeQuery.matches) { + applyDarkSkin(); + } else { + applyLightSkin(); + } + } + var activeModeIndex = 0; + var modeKeys = ["light", "dark", "auto"]; + var modeLabels = ["亮色", "暗色", "自动"]; + + var menuList = document.querySelector(".masthead .visible-links"); + var modeSwitcher = null; + if (menuList) { + modeSwitcher = document.createElement("a"); + modeSwitcher.className = "masthead__menu-item"; + modeSwitcher.textContent = modeLabels[activeModeIndex]; + modeSwitcher.href = "javascript:;"; + modeSwitcher.onclick = function () { + var nextIndex = (activeModeIndex + 1) % modeKeys.length; + settings.set("appearance_color", modeKeys[nextIndex]); + } + menuList.appendChild(modeSwitcher); + } + function applyTheme(mode) { + var newIndex = modeKeys.indexOf(mode); + if (newIndex < 0) newIndex = 0; + + if (modeKeys[activeModeIndex] === "auto") { + darkModeQuery.removeEventListener("change", autoSchemeHandler); + } + + activeModeIndex = newIndex; + var resolvedMode = modeKeys[activeModeIndex]; + + if (modeSwitcher) { + modeSwitcher.textContent = modeLabels[activeModeIndex]; + } + + if (resolvedMode === "light") { + applyLightSkin(); + } + else if (resolvedMode === "dark") { + applyDarkSkin(); + } + else { + darkModeQuery.addEventListener("change", autoSchemeHandler); + autoSchemeHandler(); + } + } + settings.onChange("appearance_color", applyTheme); + settings.onChange("appearance_skin_dark", function () { + settings.refresh("appearance_color"); + }); + settings.onChange("appearance_skin_light", function () { + settings.refresh("appearance_color"); + }); +}); diff --git a/settings.yaml b/settings.yaml new file mode 100644 index 0000000..d8d79ae --- /dev/null +++ b/settings.yaml @@ -0,0 +1,43 @@ +--- +title: 设置 +layout: settings +permalink: /settings.html +data: + - title: 外观 + settings: + appearance_color: + title: 颜色模式 + description: 用于切换站点主题颜色模式。 + options: + light: 亮色 + dark: 暗色 + auto: 自动 + appearance_skin_light: + title: 亮色皮肤 + description: 亮色模式下应用的皮肤。 + options: + default: 默认 + air: 天空 + aqua: 水蓝 + contrast: 高对比 + dark: 暗色 + dirt: 泥土 + neon: 霓虹 + mint: 薄荷 + plum: 梅紫 + sunrise: 日出 + appearance_skin_dark: + title: 暗色皮肤 + description: 暗色模式下应用的皮肤。 + options: + default: 默认 + air: 天空 + aqua: 水蓝 + contrast: 高对比 + dark: 暗色 + dirt: 泥土 + neon: 霓虹 + mint: 薄荷 + plum: 梅紫 + sunrise: 日出 +---