Compare commits

...

3 Commits

Author SHA1 Message Date
137f3e7988 update
Some checks failed
Deploy / build-and-deploy (push) Has been cancelled
2026-01-13 22:42:14 +08:00
8ccbdf4a2e 多种主题的切换 2026-01-13 21:59:11 +08:00
e3122b6068 update 2026-01-06 10:14:07 +08:00
6 changed files with 1330 additions and 156 deletions

View File

@@ -1,7 +1,6 @@
VITE_OJ=https://oj.xuyue.cc
VITE_CODE=https://code.xuyue.cc
VITE_WEB=https://web.xuyue.cc
VITE_PLAY=https://play.xuyue.cc
VITE_BOOK=https://book.xuyue.cc
VITE_HUABU=https://huabu.xuyue.cc
VITE_PPT=https://ppt.xuyue.cc/py

View File

@@ -1,7 +1,6 @@
VITE_OJ=http://10.13.114.114:81
VITE_CODE=http://10.13.114.114:82
VITE_WEB=http://10.13.114.114:91
# VITE_PLAY=http://10.13.114.114:83
VITE_BOOK=http://10.13.114.114:84
VITE_HUABU=http://10.13.114.114:85
VITE_SHUATI=http://10.13.114.114:86

View File

@@ -9,10 +9,57 @@
</head>
<body>
<button class="theme-toggle" id="themeToggle" aria-label="切换主题" title="切换深色/浅色模式">
<img src="/icons/moon.svg" alt="月亮" class="theme-icon theme-icon-moon" />
<img src="/icons/sun.svg" alt="太阳" class="theme-icon theme-icon-sun" />
</button>
<div class="theme-controls">
<label class="design-theme">
<span class="visually-hidden">设计主题</span>
<button
class="design-theme-button"
id="designThemeButton"
type="button"
aria-label="设计主题"
aria-haspopup="listbox"
aria-expanded="false"
aria-controls="designThemeList"
>
流光
</button>
<ul
class="design-theme-list"
id="designThemeList"
role="listbox"
tabindex="-1"
hidden
>
<li role="option" data-value="fluent" aria-selected="true">Fluent</li>
<li role="option" data-value="material-you" aria-selected="false">
Material You
</li>
<li role="option" data-value="terminal" aria-selected="false">
Terminal
</li>
<li role="option" data-value="cyberpunk" aria-selected="false">
Cyberpunk
</li>
</ul>
</label>
<button
class="theme-toggle"
id="themeToggle"
aria-label="切换主题"
title="切换深色/浅色模式"
>
<img
src="/icons/moon.svg"
alt="月亮"
class="theme-icon theme-icon-moon"
/>
<img
src="/icons/sun.svg"
alt="太阳"
class="theme-icon theme-icon-sun"
/>
</button>
</div>
<div id="app">
<div class="container">
<main class="main">
@@ -24,16 +71,13 @@
<a href="https://beian.miit.gov.cn" target="_blank" rel="noreferrer">
浙ICP备2023044109号
</a>
<div>
<img src="/备案图标.png" alt="备案图标" />
<a
href="https://beian.mps.gov.cn/#/query/webSearch?code=33100402331786"
rel="noreferrer"
target="_blank"
>
浙公网安备33100402331786号
</a>
</div>
<a
href="https://beian.mps.gov.cn/#/query/webSearch?code=33100402331786"
rel="noreferrer"
target="_blank"
>
浙公网安备33100402331786号
</a>
</div>
</div>
</div>

216
main.js
View File

@@ -3,18 +3,6 @@ const pins = [
// url: "https://code.xuyue.cc?query=30",
// description: "示例代码",
// },
// {
// url: "https://lc.xuyue.cc/public-forms/do0zqi0xlpe",
// description: "数据记录单",
// },
// {
// url: "https://lc.xuyue.cc/",
// description: "账号 stu 密码 123456",
// },
// {
// url: "https://play.xuyue.cc/",
// description: "选择自己的名字做小测试",
// },
]
const sites = [
@@ -42,12 +30,6 @@ const sites = [
description: "梁老师的刷题网站",
icon: "noto--paintbrush.svg",
},
{
url: import.meta.env.VITE_PLAY,
title: "限时鸭",
description: "用来练习基本的代码格式",
icon: "noto--duck.svg",
},
{
url: import.meta.env.VITE_BOOK,
title: "编程书",
@@ -99,37 +81,207 @@ document.querySelector("#sites").innerHTML =
pins.map(pin).join("") + sites.map(item).join("")
// 主题切换功能
const themeToggle = document.getElementById("themeToggle");
const themeToggle = document.getElementById("themeToggle")
const designThemeButton = document.getElementById("designThemeButton")
const designThemeList = document.getElementById("designThemeList")
const DESIGN_THEMES = ["fluent", "material-you", "terminal", "cyberpunk"]
const FORCED_DARK_DESIGN_THEMES = new Set(["terminal", "cyberpunk"])
const THEME_BEFORE_FORCED_KEY = "themeBeforeForcedDark"
// 获取保存的主题或系统偏好
function getInitialTheme() {
const savedTheme = localStorage.getItem("theme");
const savedTheme = localStorage.getItem("theme")
if (savedTheme) {
return savedTheme;
return savedTheme
}
// 如果没有保存的主题,使用系统偏好
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
: "light"
}
// 应用主题
function setTheme(theme) {
document.documentElement.setAttribute("data-theme", theme);
localStorage.setItem("theme", theme);
document.documentElement.setAttribute("data-theme", theme)
localStorage.setItem("theme", theme)
// 图标通过 CSS 自动切换显示
}
// 切换主题
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute("data-theme") || "light";
const newTheme = currentTheme === "dark" ? "light" : "dark";
setTheme(newTheme);
const designTheme =
document.documentElement.getAttribute("data-design-theme") || "fluent"
if (FORCED_DARK_DESIGN_THEMES.has(designTheme)) return
const currentTheme =
document.documentElement.getAttribute("data-theme") || "light"
const newTheme = currentTheme === "dark" ? "light" : "dark"
setTheme(newTheme)
}
function getInitialDesignTheme() {
const savedDesignTheme = localStorage.getItem("designTheme")
if (savedDesignTheme && DESIGN_THEMES.includes(savedDesignTheme)) {
return savedDesignTheme
}
return "fluent"
}
function setDesignTheme(designTheme) {
const safeDesignTheme = DESIGN_THEMES.includes(designTheme)
? designTheme
: "fluent"
const previousDesignTheme =
document.documentElement.getAttribute("data-design-theme") || "fluent"
document.documentElement.setAttribute("data-design-theme", safeDesignTheme)
localStorage.setItem("designTheme", safeDesignTheme)
const willForceDark = FORCED_DARK_DESIGN_THEMES.has(safeDesignTheme)
const didForceDark = FORCED_DARK_DESIGN_THEMES.has(previousDesignTheme)
if (willForceDark) {
if (!didForceDark) {
const currentTheme =
document.documentElement.getAttribute("data-theme") || "light"
localStorage.setItem(THEME_BEFORE_FORCED_KEY, currentTheme)
}
setTheme("dark")
} else if (didForceDark) {
const restoreTheme =
localStorage.getItem(THEME_BEFORE_FORCED_KEY) ||
localStorage.getItem("themeBeforeTerminal")
if (restoreTheme === "dark" || restoreTheme === "light") {
setTheme(restoreTheme)
}
localStorage.removeItem(THEME_BEFORE_FORCED_KEY)
localStorage.removeItem("themeBeforeTerminal")
}
if (themeToggle) {
themeToggle.disabled = willForceDark
themeToggle.setAttribute("aria-disabled", willForceDark ? "true" : "false")
themeToggle.tabIndex = willForceDark ? -1 : 0
}
}
function getDesignThemeLabel(designTheme) {
const optionEl = designThemeList?.querySelector(
`[role="option"][data-value="${designTheme}"]`,
)
if (optionEl) return optionEl.textContent?.trim() || "流光"
const fallback = {
fluent: "流光",
"material-you": "Material You",
terminal: "终端",
cyberpunk: "Cyberpunk",
}
return fallback[designTheme] || "流光"
}
function setSelectedDesignThemeUI(designTheme) {
if (!designThemeList) return
const options = [...designThemeList.querySelectorAll('[role="option"]')]
options.forEach((el) => {
el.setAttribute(
"aria-selected",
el.getAttribute("data-value") === designTheme ? "true" : "false",
)
})
if (designThemeButton) {
designThemeButton.textContent = getDesignThemeLabel(designTheme)
}
}
function setDesignThemeMenuOpen(open) {
if (!designThemeButton || !designThemeList) return
designThemeButton.setAttribute("aria-expanded", open ? "true" : "false")
designThemeList.hidden = !open
if (open) {
designThemeList.focus()
}
}
function getCurrentDesignTheme() {
return document.documentElement.getAttribute("data-design-theme") || "fluent"
}
const titleEl = document.querySelector(".title")
if (titleEl && !titleEl.dataset.text) {
titleEl.dataset.text = titleEl.textContent?.trim() || ""
}
const subtitleEl = document.querySelector(".subtitle")
if (subtitleEl && !subtitleEl.dataset.text) {
subtitleEl.dataset.text = subtitleEl.textContent?.trim() || ""
}
// 初始化主题
const initialTheme = getInitialTheme();
setTheme(initialTheme);
const initialTheme = getInitialTheme()
setTheme(initialTheme)
const initialDesignTheme = getInitialDesignTheme()
setDesignTheme(initialDesignTheme)
setSelectedDesignThemeUI(initialDesignTheme)
setDesignThemeMenuOpen(false)
if (designThemeButton && designThemeList) {
designThemeButton.addEventListener("click", () => {
const isOpen = designThemeButton.getAttribute("aria-expanded") === "true"
setDesignThemeMenuOpen(!isOpen)
})
designThemeList.addEventListener("click", (e) => {
const option = e.target.closest?.('[role="option"][data-value]')
if (!option) return
const value = option.getAttribute("data-value")
setDesignTheme(value)
setSelectedDesignThemeUI(value)
setDesignThemeMenuOpen(false)
})
document.addEventListener("click", (e) => {
if (!designThemeButton || !designThemeList) return
const clickedInside =
designThemeButton.contains(e.target) || designThemeList.contains(e.target)
if (!clickedInside) setDesignThemeMenuOpen(false)
})
document.addEventListener("keydown", (e) => {
const isOpen = designThemeButton.getAttribute("aria-expanded") === "true"
if (!isOpen) return
if (e.key === "Escape") {
e.preventDefault()
setDesignThemeMenuOpen(false)
designThemeButton.focus()
return
}
const options = [...designThemeList.querySelectorAll('[role="option"]')]
if (!options.length) return
const current = getCurrentDesignTheme()
const currentIndex = Math.max(
0,
options.findIndex((el) => el.getAttribute("data-value") === current),
)
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
e.preventDefault()
const delta = e.key === "ArrowDown" ? 1 : -1
const nextIndex = (currentIndex + delta + options.length) % options.length
const nextValue = options[nextIndex].getAttribute("data-value")
setDesignTheme(nextValue)
setSelectedDesignThemeUI(nextValue)
return
}
if (e.key === "Enter" || e.key === " ") {
e.preventDefault()
setDesignThemeMenuOpen(false)
designThemeButton.focus()
}
})
}
// 监听系统主题变化(仅在用户未手动设置时)
window
@@ -137,9 +289,9 @@ window
.addEventListener("change", (e) => {
// 如果用户没有手动设置过主题,则跟随系统
if (!localStorage.getItem("theme")) {
setTheme(e.matches ? "dark" : "light");
setTheme(e.matches ? "dark" : "light")
}
});
})
// 绑定点击事件
themeToggle.addEventListener("click", toggleTheme);
themeToggle.addEventListener("click", toggleTheme)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

1172
style.css

File diff suppressed because it is too large Load Diff