324 lines
17 KiB
HTML
324 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https: data:; script-src 'self' 'unsafe-inline'; connect-src https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https: *;">
|
||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' fill='%23111111'/%3E%3Crect x='18' y='18' width='28' height='28' fill='%23ff3b30'/%3E%3C/svg%3E">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>hyonglin.top</title>
|
||
<style>
|
||
/* ===== Swiss / Editorial:浅色为主,深色自适应 ===== */
|
||
:root {
|
||
--bg: #f4f4f2;
|
||
--text: #111111;
|
||
--muted: #6b6b70;
|
||
--line: rgba(17,17,17,.22);
|
||
--accent: #ff3b30;
|
||
--mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
||
}
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--bg: #0f0f10;
|
||
--text: #f4f4f2;
|
||
--muted: #8a8a8e;
|
||
--line: rgba(255,255,255,.2);
|
||
--accent: #ff453a;
|
||
}
|
||
}
|
||
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
html, body { height: 100%; }
|
||
body {
|
||
font-family: "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
min-height: 100vh;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
::selection { background: var(--accent); color: #fff; }
|
||
|
||
.page { max-width: 1240px; margin: 0 auto; padding: 0 clamp(20px, 5vw, 64px) 0; }
|
||
|
||
/* ===== 入场:克制的淡入上移 ===== */
|
||
.reveal { animation: fadeup .7s ease both; animation-delay: var(--d, 0s); }
|
||
@keyframes fadeup { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
|
||
|
||
/* ===== 报头 ===== */
|
||
.masthead { padding-top: 40px; }
|
||
.meta-row { display: flex; justify-content: space-between; gap: 16px; font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line); padding-bottom: 14px; }
|
||
.meta-row .sq { display: inline-block; width: 8px; height: 8px; background: var(--accent); margin-right: 10px; vertical-align: middle; }
|
||
h1 { font-size: clamp(3rem, 9vw, 7.5rem); font-weight: 200; letter-spacing: -.03em; line-height: .98; margin-top: clamp(24px, 4vh, 48px); }
|
||
p.sub { margin-top: 14px; font-size: .8rem; letter-spacing: .35em; color: var(--muted); text-transform: uppercase; }
|
||
|
||
/* ===== 数据栏:天气 / 日期 / 时间(杂志数据页) ===== */
|
||
.data { display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid var(--line); margin-top: clamp(28px, 5vh, 56px); }
|
||
.cell { padding: 26px 0 30px; min-width: 0; }
|
||
.cell + .cell { border-left: 1px solid var(--line); padding-left: clamp(18px, 3vw, 40px); }
|
||
.label { display: flex; align-items: center; gap: 9px; font-size: .68rem; letter-spacing: .22em; text-transform: uppercase; color: var(--muted); margin-bottom: 16px; }
|
||
.label::before { content: ""; width: 6px; height: 6px; background: var(--accent); flex-shrink: 0; }
|
||
.big { font-size: clamp(2rem, 5vw, 3.6rem); font-weight: 250; font-variant-numeric: tabular-nums; letter-spacing: -.01em; line-height: 1.05; display: flex; align-items: baseline; gap: .28em; white-space: nowrap; }
|
||
/* 日期字符串比时钟长(含"周X"),单独降一档保证不越出格子 */
|
||
.big.date { font-size: clamp(1.5rem, 3.2vw, 2.6rem); }
|
||
.sky .emoji { font-size: .62em; transform: translateY(-.04em); }
|
||
.wcity { margin-top: 10px; font-size: .78rem; color: var(--muted); letter-spacing: .06em; min-height: 1.2em; }
|
||
|
||
/* ===== 搜索行 ===== */
|
||
form.search { display: flex; align-items: center; gap: clamp(12px, 2vw, 24px); padding: 18px 0; border-top: 1px solid var(--line); margin-top: -1px; }
|
||
.slabel { font-size: .68rem; letter-spacing: .22em; text-transform: uppercase; color: var(--muted); flex-shrink: 0; }
|
||
form.search select {
|
||
cursor: pointer; flex-shrink: 0;
|
||
font-family: inherit; font-size: .85rem; color: var(--text);
|
||
background: transparent; border: 1px solid var(--line); border-radius: 0;
|
||
padding: 9px 12px; outline: none; max-width: 130px;
|
||
}
|
||
form.search select:focus-visible { border-color: var(--accent); }
|
||
form.search input { flex: 1; min-width: 0; background: none; border: none; outline: none; color: var(--text); font-family: inherit; font-size: 1rem; padding: 8px 0; caret-color: var(--accent); }
|
||
form.search input::placeholder { color: var(--muted); }
|
||
form.search button {
|
||
border: 1px solid var(--line); background: transparent; cursor: pointer; flex-shrink: 0;
|
||
width: 44px; height: 38px; font-size: 1.05rem; color: var(--text);
|
||
transition: background .15s ease, color .15s ease, border-color .15s ease;
|
||
}
|
||
form.search button:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||
|
||
/* ===== 分组:编号索引式列表 ===== */
|
||
.group { border-top: 1px solid var(--line); margin-top: -1px; }
|
||
.ghead { display: grid; grid-template-columns: clamp(64px, 8vw, 96px) 1fr auto; align-items: baseline; gap: 18px; padding: 20px 0 6px; }
|
||
.ghead .num { font-size: clamp(1.5rem, 2.6vw, 2.1rem); font-weight: 300; color: var(--accent); font-variant-numeric: tabular-nums; letter-spacing: .02em; }
|
||
.ghead h2 { font-size: .82rem; font-weight: 600; letter-spacing: .24em; text-transform: uppercase; display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
|
||
.ghead h2 .en { font-family: var(--mono); font-size: .68rem; font-weight: 400; letter-spacing: .18em; color: var(--muted); text-transform: uppercase; }
|
||
.ghead .count { font-family: var(--mono); font-size: .72rem; color: var(--muted); letter-spacing: .12em; }
|
||
|
||
ul.rows { list-style: none; }
|
||
ul.rows li + li a, ul.rows li:first-child a { border-top: 1px solid var(--line); }
|
||
ul.rows a {
|
||
display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
|
||
padding: 15px 0; text-decoration: none; color: var(--text);
|
||
transition: color .15s ease;
|
||
}
|
||
ul.rows .name { font-size: clamp(1rem, 1.6vw, 1.18rem); font-weight: 450; letter-spacing: .01em; }
|
||
ul.rows .arrow { opacity: 0; transform: translateX(-6px); color: var(--accent); transition: opacity .15s ease, transform .15s ease; }
|
||
ul.rows a:hover .name, ul.rows a:focus-visible .name { color: var(--accent); }
|
||
ul.rows a:hover .arrow, ul.rows a:focus-visible .arrow { opacity: 1; transform: none; }
|
||
ul.rows .dom { margin-left: auto; font-family: var(--mono); font-size: .72rem; color: var(--muted); letter-spacing: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 56%; }
|
||
a:focus-visible, button:focus-visible, select:focus-visible { outline: 1px solid var(--accent); outline-offset: 3px; }
|
||
|
||
/* ===== 页脚:版本切换行 ===== */
|
||
.foot { display: flex; justify-content: space-between; align-items: baseline; gap: 18px; flex-wrap: wrap; border-top: 1px solid var(--line); margin-top: clamp(36px, 7vh, 72px); padding: 22px 0 40px; }
|
||
.fbrand { font-size: .9rem; font-weight: 600; letter-spacing: .04em; }
|
||
nav.versions { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; font-size: .78rem; color: var(--muted); }
|
||
nav.versions .sep { opacity: .6; }
|
||
nav.versions a { color: var(--muted); text-decoration: none; transition: color .15s ease; }
|
||
nav.versions a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 4px; }
|
||
nav.versions .path { font-family: var(--mono); font-size: .72rem; margin-left: 3px; }
|
||
nav.versions .current { color: var(--text); }
|
||
nav.versions .current::after { content: "(当前)"; color: var(--accent); font-size: .72rem; margin-left: 4px; }
|
||
|
||
/* ===== 响应式:窄屏分区堆叠 ===== */
|
||
@media (max-width: 720px) {
|
||
.data { grid-template-columns: 1fr; }
|
||
.cell + .cell { border-left: none; padding-left: 0; border-top: 1px solid var(--line); }
|
||
.ghead { grid-template-columns: auto 1fr; }
|
||
.ghead .count { display: none; }
|
||
ul.rows a { gap: 8px; }
|
||
ul.rows .dom { margin-left: 0; max-width: 100%; width: 100%; order: 3; text-align: left; }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.reveal { animation: none; }
|
||
ul.rows a, ul.rows .arrow, form.search button, nav.versions a { transition: none; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main class="page">
|
||
<!-- 报头 -->
|
||
<header class="masthead reveal" style="--d:.02s">
|
||
<div class="meta-row">
|
||
<span><span class="sq"></span>HYONGLIN.TOP — INDEX</span>
|
||
<span>NAVIGATION / 导航索引</span>
|
||
</div>
|
||
<h1>hyonglin.top</h1>
|
||
<p class="sub">个人服务导航 · 随时可达</p>
|
||
</header>
|
||
|
||
<!-- 数据栏:天气 / 日期 / 时间 -->
|
||
<section class="data reveal" style="--d:.1s" aria-label="天气与时间">
|
||
<div class="cell sky">
|
||
<span class="label">天气 Weather</span>
|
||
<span class="big"><span class="emoji">☀️</span><span class="wtxt">获取中…</span></span>
|
||
<span class="wcity"></span>
|
||
</div>
|
||
<div class="cell">
|
||
<span class="label">日期 Date</span>
|
||
<span class="big date" id="dateval">----</span>
|
||
</div>
|
||
<div class="cell">
|
||
<span class="label">时间 Time</span>
|
||
<span class="big" id="clockval">--:--:--</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 搜索 -->
|
||
<form class="search reveal" style="--d:.18s" action="https://www.bing.com/search" method="get" target="_blank" rel="noopener">
|
||
<span class="slabel">Search</span>
|
||
<select name="engine" id="engine" aria-label="搜索引擎">
|
||
<option value="bing" selected>Bing</option>
|
||
<option value="google">Google</option>
|
||
<option value="baidu">百度</option>
|
||
<option value="duckduckgo">DuckDuckGo</option>
|
||
</select>
|
||
<input type="text" name="q" placeholder="输入关键词,回车搜索…" autocomplete="off" aria-label="搜索">
|
||
<button type="submit" aria-label="搜索">→</button>
|
||
</form>
|
||
|
||
<!-- 01 自建服务 -->
|
||
<section class="group reveal" style="--d:.26s">
|
||
<header class="ghead">
|
||
<span class="num">01</span>
|
||
<h2>自建服务<span class="en">Self-Hosted</span></h2>
|
||
<span class="count">4 ITEMS</span>
|
||
</header>
|
||
<ul class="rows">
|
||
<li><a href="https://note.hyonglin.top"><span class="name">笔记</span><span class="arrow">→</span><span class="dom">note.hyonglin.top · SilverBullet</span></a></li>
|
||
<li><a href="https://git.hyonglin.top"><span class="name">Git 服务</span><span class="arrow">→</span><span class="dom">git.hyonglin.top · Gitea</span></a></li>
|
||
<li><a href="https://ssh.hyonglin.top"><span class="name">网页 SSH 终端</span><span class="arrow">→</span><span class="dom">ssh.hyonglin.top</span></a></li>
|
||
<li><a href="https://frp.hyonglin.top"><span class="name">frp 管理面板</span><span class="arrow">→</span><span class="dom">frp.hyonglin.top</span></a></li>
|
||
</ul>
|
||
</section>
|
||
|
||
<!-- 02 AI 助手 -->
|
||
<section class="group reveal" style="--d:.34s">
|
||
<header class="ghead">
|
||
<span class="num">02</span>
|
||
<h2>AI 助手<span class="en">AI Assistants</span></h2>
|
||
<span class="count">2 ITEMS</span>
|
||
</header>
|
||
<ul class="rows">
|
||
<li><a href="https://chat.deepseek.com/" target="_blank" rel="noopener"><span class="name">DeepSeek</span><span class="arrow">→</span><span class="dom">chat.deepseek.com</span></a></li>
|
||
<li><a href="https://www.doubao.com/chat/" target="_blank" rel="noopener"><span class="name">豆包</span><span class="arrow">→</span><span class="dom">doubao.com</span></a></li>
|
||
</ul>
|
||
</section>
|
||
|
||
<!-- 03 云服务 -->
|
||
<section class="group reveal" style="--d:.42s">
|
||
<header class="ghead">
|
||
<span class="num">03</span>
|
||
<h2>云服务<span class="en">Cloud Services</span></h2>
|
||
<span class="count">3 ITEMS</span>
|
||
</header>
|
||
<ul class="rows">
|
||
<li><a href="https://dash.cloudflare.com/" target="_blank" rel="noopener"><span class="name">Cloudflare</span><span class="arrow">→</span><span class="dom">dash.cloudflare.com</span></a></li>
|
||
<li><a href="https://auth.huaweicloud.com/" target="_blank" rel="noopener"><span class="name">华为云</span><span class="arrow">→</span><span class="dom">auth.huaweicloud.com</span></a></li>
|
||
<li><a href="https://console.cloud.tencent.com/" target="_blank" rel="noopener"><span class="name">腾讯云</span><span class="arrow">→</span><span class="dom">console.cloud.tencent.com</span></a></li>
|
||
</ul>
|
||
</section>
|
||
|
||
<!-- 04 常用 -->
|
||
<section class="group reveal" style="--d:.5s">
|
||
<header class="ghead">
|
||
<span class="num">04</span>
|
||
<h2>常用<span class="en">Utilities</span></h2>
|
||
<span class="count">3 ITEMS</span>
|
||
</header>
|
||
<ul class="rows">
|
||
<li><a href="https://wx.mail.qq.com/" target="_blank" rel="noopener"><span class="name">QQ 邮箱</span><span class="arrow">→</span><span class="dom">wx.mail.qq.com</span></a></li>
|
||
<li><a href="https://www.bing.com/" target="_blank" rel="noopener"><span class="name">Bing 搜索</span><span class="arrow">→</span><span class="dom">bing.com</span></a></li>
|
||
<li><a href="https://www.bilibili.com/" target="_blank" rel="noopener"><span class="name">哔哩哔哩</span><span class="arrow">→</span><span class="dom">bilibili.com</span></a></li>
|
||
</ul>
|
||
</section>
|
||
|
||
<!-- 页脚:版本切换 -->
|
||
<footer class="foot reveal" style="--d:.58s">
|
||
<span class="fbrand">hyonglin.top</span>
|
||
<nav class="versions" aria-label="版本切换">
|
||
<a href="/terminal/">终端版<span class="path">/terminal/</span></a><span class="sep">·</span>
|
||
<a href="/">Bento 版<span class="path">/</span></a><span class="sep">·</span>
|
||
<a href="/brutal/">Brutal 版<span class="path">/brutal/</span></a><span class="sep">·</span>
|
||
<span class="current">Swiss 版<span class="path">/swiss/</span></span><span class="sep">·</span>
|
||
<a href="/hud/">HUD 版<span class="path">/hud/</span></a>
|
||
</nav>
|
||
</footer>
|
||
</main>
|
||
|
||
<script>
|
||
/* ===== 搜索引擎选择 ===== */
|
||
(function(){
|
||
var sel = document.getElementById('engine');
|
||
if (!sel) return;
|
||
var ENGINES = {
|
||
bing: 'https://www.bing.com/search?q=',
|
||
google: 'https://www.google.com/search?q=',
|
||
baidu: 'https://www.baidu.com/s?wd=',
|
||
duckduckgo: 'https://duckduckgo.com/?q='
|
||
};
|
||
var form = sel.closest('form');
|
||
function apply() { form.action = ENGINES[sel.value] || ENGINES.bing; }
|
||
sel.addEventListener('change', apply);
|
||
apply();
|
||
})();
|
||
|
||
/* ===== 日期 + 时钟 ===== */
|
||
var week = ['日','一','二','三','四','五','六'];
|
||
function pad2(n) { return (n < 10 ? '0' : '') + n; }
|
||
function updateClock() {
|
||
var now = new Date();
|
||
var c = document.getElementById('clockval');
|
||
if (c) c.textContent = pad2(now.getHours()) + ':' + pad2(now.getMinutes()) + ':' + pad2(now.getSeconds());
|
||
var d = document.getElementById('dateval');
|
||
if (d) d.textContent = now.getFullYear() + '-' + pad2(now.getMonth()+1) + '-' + pad2(now.getDate()) + ' 周' + week[now.getDay()];
|
||
}
|
||
setInterval(updateClock, 1000);
|
||
updateClock();
|
||
|
||
/* ===== 天气:GPS 定位 + Open-Meteo(不依赖 IP) ===== */
|
||
var emojiBox = function(){ return document.querySelector('.sky .emoji'); };
|
||
var tempBox = function(){ return document.querySelector('.wtxt'); };
|
||
var cityBox = function(){ return document.querySelector('.wcity'); };
|
||
|
||
var WMO = {
|
||
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 wmo(w) { return WMO[w] || '🌡️'; }
|
||
|
||
function setWeather(temp, wcode, city) {
|
||
if (tempBox()) tempBox().textContent = temp + '°C';
|
||
if (emojiBox()) emojiBox().textContent = wmo(wcode);
|
||
if (city && cityBox()) cityBox().textContent = city;
|
||
}
|
||
|
||
function getWeather(lat, lon, city) {
|
||
var url = 'https://api.open-meteo.com/v1/forecast?latitude=' + lat + '&longitude=' + lon +
|
||
'¤t_weather=true&timezone=auto';
|
||
fetch(url).then(function(r){ return r.json(); }).then(function(d){
|
||
var cw = d.current_weather || {};
|
||
setWeather(Math.round(cw.temperature), cw.weathercode, city);
|
||
}).catch(function(){ tempBox() && (tempBox().textContent = '天气获取失败'); });
|
||
}
|
||
|
||
// 优先浏览器 GPS 定位;失败则 ipwho.is 按 IP 定位;再失败显示默认城市(北京)
|
||
var DEFAULT_LOC = { lat: 39.9042, lon: 116.4074, city: '北京' };
|
||
|
||
function byIP() {
|
||
fetch('https://ipwho.is/').then(function(r){ return r.json(); }).then(function(d){
|
||
if (d && d.latitude && d.longitude) getWeather(d.latitude, d.longitude, d.city || '');
|
||
else { getWeather(DEFAULT_LOC.lat, DEFAULT_LOC.lon, DEFAULT_LOC.city); }
|
||
}).catch(function(){ getWeather(DEFAULT_LOC.lat, DEFAULT_LOC.lon, DEFAULT_LOC.city); });
|
||
}
|
||
|
||
if (navigator.geolocation) {
|
||
navigator.geolocation.getCurrentPosition(function(pos){
|
||
getWeather(pos.coords.latitude, pos.coords.longitude, '');
|
||
}, byIP, { timeout: 8000 });
|
||
} else {
|
||
byIP();
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|