-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
232 lines (197 loc) · 6.18 KB
/
Copy pathscript.js
File metadata and controls
232 lines (197 loc) · 6.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// === 主题切换 ===
const themeToggle = document.getElementById("themeToggle");
const html = document.documentElement;
const savedTheme = localStorage.getItem("theme") || "light";
html.setAttribute("data-theme", savedTheme);
updateThemeIcon(savedTheme);
function updateThemeIcon(theme) {
const icon = themeToggle.querySelector("i");
icon.className = theme === "dark" ? "fas fa-sun" : "fas fa-moon";
}
themeToggle.addEventListener("click", () => {
const current = html.getAttribute("data-theme");
const next = current === "dark" ? "light" : "dark";
html.setAttribute("data-theme", next);
localStorage.setItem("theme", next);
updateThemeIcon(next);
});
const dateLine = document.getElementById("dateLine");
const timeLine = document.getElementById("timeLine");
const weatherLine = document.getElementById("weatherLine");
const quoteText = document.getElementById("quoteText");
const quoteAuthor = document.getElementById("quoteAuthor");
const homePhotographyImage = document.getElementById("homePhotographyImage");
const homePhotographyCaption = document.getElementById("homePhotographyCaption");
const photoGallery = document.getElementById("photoGallery");
const fallbackPhotographyImages = [
{
title: "武汉大学大暑",
src: "./pictures/武汉大学大暑.jpg",
description: "夏日校园里的光影与热烈。"
},
{
title: "小猫",
src: "./pictures/小猫.jpg",
description: "镜头里安静又灵动的片刻。"
}
];
const photographyImages = window.photographyImages || fallbackPhotographyImages;
const weatherMap = {
0: "晴",
1: "多云",
2: "局部多云",
3: "阴",
45: "雾",
48: "冻雾",
51: "小毛雨",
53: "毛雨",
55: "大毛雨",
56: "冻毛雨",
57: "强冻毛雨",
61: "小雨",
63: "中雨",
65: "大雨",
66: "冻雨",
67: "强冻雨",
71: "小雪",
73: "中雪",
75: "大雪",
77: "冰粒",
80: "阵雨",
81: "强阵雨",
82: "暴雨",
85: "阵雪",
86: "强阵雪",
95: "雷暴",
96: "雷暴伴小冰雹",
99: "雷暴伴大冰雹"
};
function updateClock() {
const now = new Date();
if (dateLine) {
dateLine.textContent = new Intl.DateTimeFormat("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
weekday: "long",
timeZone: "Asia/Shanghai"
}).format(now);
}
if (timeLine) {
timeLine.textContent = new Intl.DateTimeFormat("zh-CN", {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
timeZone: "Asia/Shanghai"
}).format(now);
}
}
async function fetchWithTimeout(url, timeoutMs = 7000) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response;
} finally {
clearTimeout(timer);
}
}
async function fetchJsonSmart(url) {
const proxyUrl = `https://api.allorigins.win/raw?url=${encodeURIComponent(url)}`;
try {
const direct = await fetchWithTimeout(url);
return await direct.json();
} catch (_) {
const proxied = await fetchWithTimeout(proxyUrl);
return await proxied.json();
}
}
async function loadWuhanWeather() {
if (!weatherLine) {
return;
}
const url = "https://api.open-meteo.com/v1/forecast?latitude=30.5928&longitude=114.3055¤t=temperature_2m,weather_code,wind_speed_10m&timezone=Asia%2FShanghai";
try {
const data = await fetchJsonSmart(url);
const current = data.current;
if (!current) {
throw new Error("Missing weather data");
}
const temp = Math.round(current.temperature_2m);
const wind = Math.round(current.wind_speed_10m);
const weatherText = weatherMap[current.weather_code] || "天气正常";
weatherLine.textContent = `武汉市 ${weatherText} ${temp}°C 风速 ${wind} km/h`;
} catch (error) {
weatherLine.textContent = "武汉市 天气数据暂不可用";
}
}
async function loadRandomQuote() {
if (!quoteText || !quoteAuthor) {
return;
}
const url = "https://v1.hitokoto.cn/?c=d&c=i&c=k&encode=json";
try {
const data = await fetchJsonSmart(url);
const text = data.hitokoto || "保持热爱,奔赴山海。";
const source = data.from_who || data.from || "佚名";
quoteText.textContent = `"${text}"`;
quoteAuthor.textContent = `- ${source}`;
} catch (error) {
quoteText.textContent = "\"保持热爱,奔赴山海。\"";
quoteAuthor.textContent = "- 佚名";
}
}
updateClock();
setInterval(updateClock, 1000);
loadWuhanWeather();
setInterval(loadWuhanWeather, 10 * 60 * 1000);
loadRandomQuote();
setInterval(loadRandomQuote, 30 * 60 * 1000);
function loadHomePhotographyPreview() {
if (!homePhotographyImage || !homePhotographyCaption || photographyImages.length === 0) {
return;
}
const randomIndex = Math.floor(Math.random() * photographyImages.length);
const image = photographyImages[randomIndex];
homePhotographyImage.src = image.src;
homePhotographyImage.alt = image.title;
homePhotographyCaption.textContent = `${image.title} · ${image.description}`;
}
function renderPhotoGallery() {
if (!photoGallery) {
return;
}
photoGallery.innerHTML = photographyImages.map((image) => `
<a class="material-card photo-item" href="${image.src}" target="_blank" rel="noopener">
<img src="${image.src}" alt="${image.title}" loading="lazy">
<div class="photo-meta">
<h3>${image.title}</h3>
<p>${image.description}</p>
</div>
</a>
`).join("");
}
loadHomePhotographyPreview();
renderPhotoGallery();
// === 返回顶部 ===
const backToTop = document.getElementById("backToTop");
window.addEventListener("scroll", () => {
if (window.scrollY > 400) {
backToTop.classList.add("visible");
} else {
backToTop.classList.remove("visible");
}
}, { passive: true });
backToTop.addEventListener("click", () => {
window.scrollTo({ top: 0, behavior: "smooth" });
});
window.addEventListener("load", () => {
const loader = document.getElementById("pageLoader");
if (loader) {
setTimeout(() => loader.classList.add("hidden"), 300);
}
});