Compare commits
3 Commits
263283b215
...
137f3e7988
| Author | SHA1 | Date | |
|---|---|---|---|
| 137f3e7988 | |||
| 8ccbdf4a2e | |||
| e3122b6068 |
@@ -1,7 +1,6 @@
|
|||||||
VITE_OJ=https://oj.xuyue.cc
|
VITE_OJ=https://oj.xuyue.cc
|
||||||
VITE_CODE=https://code.xuyue.cc
|
VITE_CODE=https://code.xuyue.cc
|
||||||
VITE_WEB=https://web.xuyue.cc
|
VITE_WEB=https://web.xuyue.cc
|
||||||
VITE_PLAY=https://play.xuyue.cc
|
|
||||||
VITE_BOOK=https://book.xuyue.cc
|
VITE_BOOK=https://book.xuyue.cc
|
||||||
VITE_HUABU=https://huabu.xuyue.cc
|
VITE_HUABU=https://huabu.xuyue.cc
|
||||||
VITE_PPT=https://ppt.xuyue.cc/py
|
VITE_PPT=https://ppt.xuyue.cc/py
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
VITE_OJ=http://10.13.114.114:81
|
VITE_OJ=http://10.13.114.114:81
|
||||||
VITE_CODE=http://10.13.114.114:82
|
VITE_CODE=http://10.13.114.114:82
|
||||||
VITE_WEB=http://10.13.114.114:91
|
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_BOOK=http://10.13.114.114:84
|
||||||
VITE_HUABU=http://10.13.114.114:85
|
VITE_HUABU=http://10.13.114.114:85
|
||||||
VITE_SHUATI=http://10.13.114.114:86
|
VITE_SHUATI=http://10.13.114.114:86
|
||||||
56
index.html
56
index.html
@@ -9,10 +9,57 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<button class="theme-toggle" id="themeToggle" aria-label="切换主题" title="切换深色/浅色模式">
|
<div class="theme-controls">
|
||||||
<img src="/icons/moon.svg" alt="月亮" class="theme-icon theme-icon-moon" />
|
<label class="design-theme">
|
||||||
<img src="/icons/sun.svg" alt="太阳" class="theme-icon theme-icon-sun" />
|
<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>
|
</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 id="app">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<main class="main">
|
<main class="main">
|
||||||
@@ -24,8 +71,6 @@
|
|||||||
<a href="https://beian.miit.gov.cn" target="_blank" rel="noreferrer">
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noreferrer">
|
||||||
浙ICP备2023044109号
|
浙ICP备2023044109号
|
||||||
</a>
|
</a>
|
||||||
<div>
|
|
||||||
<img src="/备案图标.png" alt="备案图标" />
|
|
||||||
<a
|
<a
|
||||||
href="https://beian.mps.gov.cn/#/query/webSearch?code=33100402331786"
|
href="https://beian.mps.gov.cn/#/query/webSearch?code=33100402331786"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
@@ -36,7 +81,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<script type="module" src="/main.js"></script>
|
<script type="module" src="/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
216
main.js
216
main.js
@@ -3,18 +3,6 @@ const pins = [
|
|||||||
// url: "https://code.xuyue.cc?query=30",
|
// url: "https://code.xuyue.cc?query=30",
|
||||||
// description: "示例代码",
|
// 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 = [
|
const sites = [
|
||||||
@@ -42,12 +30,6 @@ const sites = [
|
|||||||
description: "梁老师的刷题网站",
|
description: "梁老师的刷题网站",
|
||||||
icon: "noto--paintbrush.svg",
|
icon: "noto--paintbrush.svg",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
url: import.meta.env.VITE_PLAY,
|
|
||||||
title: "限时鸭",
|
|
||||||
description: "用来练习基本的代码格式",
|
|
||||||
icon: "noto--duck.svg",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
url: import.meta.env.VITE_BOOK,
|
url: import.meta.env.VITE_BOOK,
|
||||||
title: "编程书",
|
title: "编程书",
|
||||||
@@ -99,37 +81,207 @@ document.querySelector("#sites").innerHTML =
|
|||||||
pins.map(pin).join("") + sites.map(item).join("")
|
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() {
|
function getInitialTheme() {
|
||||||
const savedTheme = localStorage.getItem("theme");
|
const savedTheme = localStorage.getItem("theme")
|
||||||
if (savedTheme) {
|
if (savedTheme) {
|
||||||
return savedTheme;
|
return savedTheme
|
||||||
}
|
}
|
||||||
// 如果没有保存的主题,使用系统偏好
|
// 如果没有保存的主题,使用系统偏好
|
||||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
? "dark"
|
? "dark"
|
||||||
: "light";
|
: "light"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用主题
|
// 应用主题
|
||||||
function setTheme(theme) {
|
function setTheme(theme) {
|
||||||
document.documentElement.setAttribute("data-theme", theme);
|
document.documentElement.setAttribute("data-theme", theme)
|
||||||
localStorage.setItem("theme", theme);
|
localStorage.setItem("theme", theme)
|
||||||
// 图标通过 CSS 自动切换显示
|
// 图标通过 CSS 自动切换显示
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换主题
|
// 切换主题
|
||||||
function toggleTheme() {
|
function toggleTheme() {
|
||||||
const currentTheme = document.documentElement.getAttribute("data-theme") || "light";
|
const designTheme =
|
||||||
const newTheme = currentTheme === "dark" ? "light" : "dark";
|
document.documentElement.getAttribute("data-design-theme") || "fluent"
|
||||||
setTheme(newTheme);
|
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();
|
const initialTheme = getInitialTheme()
|
||||||
setTheme(initialTheme);
|
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
|
window
|
||||||
@@ -137,9 +289,9 @@ window
|
|||||||
.addEventListener("change", (e) => {
|
.addEventListener("change", (e) => {
|
||||||
// 如果用户没有手动设置过主题,则跟随系统
|
// 如果用户没有手动设置过主题,则跟随系统
|
||||||
if (!localStorage.getItem("theme")) {
|
if (!localStorage.getItem("theme")) {
|
||||||
setTheme(e.matches ? "dark" : "light");
|
setTheme(e.matches ? "dark" : "light")
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
// 绑定点击事件
|
// 绑定点击事件
|
||||||
themeToggle.addEventListener("click", toggleTheme);
|
themeToggle.addEventListener("click", toggleTheme)
|
||||||
|
|||||||
BIN
public/备案图标.png
BIN
public/备案图标.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
Reference in New Issue
Block a user