-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathguestbook.html
More file actions
206 lines (197 loc) · 9.6 KB
/
Copy pathguestbook.html
File metadata and controls
206 lines (197 loc) · 9.6 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
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Pinklemon · Guestbook</title>
<meta name="description" content="给 Pinklemon 留言" />
<meta name="color-scheme" content="light dark" />
<style>
:root{
--bg:#0b0c10; --panel:#111218; --text:#e9eef4; --muted:#aab3bf; --line:#1a1c25;
--shadow:rgba(0,0,0,.35); --radius:18px; --maxw:780px;
}
@media (prefers-color-scheme: light){
:root{ --bg:#f7fafc; --panel:#fff; --text:#1a1f2b; --muted:#5b6472; --line:#e8edf3; --shadow:rgba(2,6,23,.08); }
}
*{box-sizing:border-box}
body{
margin:0;
background:
radial-gradient(1000px 500px at -10% 0%, rgba(125,211,252,.13), transparent 60%),
radial-gradient(900px 500px at 110% 100%, rgba(244,114,182,.13), transparent 60%),
var(--bg);
color:var(--text);
font:16px/1.7 ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Arial, sans-serif;
}
a{color:inherit;text-decoration:none}
.wrap{max-width:var(--maxw);margin:0 auto;padding:24px 20px 56px}
.nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}
.chip{padding:9px 12px;border:1px solid var(--line);border-radius:999px}
.panel{
border:1px solid var(--line);border-radius:var(--radius);
background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(0,0,0,.03)), var(--panel);
box-shadow:0 18px 36px var(--shadow);padding:20px
}
.muted{color:var(--muted)}
.hr{height:1px;background:linear-gradient(90deg, transparent, var(--line), transparent);margin:20px 0}
.tabs{display:flex;gap:10px;flex-wrap:wrap}
.tab-btn{
padding:10px 14px;border-radius:999px;border:1px solid var(--line);
background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(0,0,0,.03));
cursor:pointer;font-weight:700
}
.tab-btn[aria-selected="true"]{
border-color:transparent;
box-shadow:0 10px 24px var(--shadow);
background:radial-gradient(200% 100% at 0% 0%, rgba(125,211,252,.2), transparent 60%),
radial-gradient(200% 100% at 100% 100%, rgba(244,114,182,.2), transparent 60%),
linear-gradient(180deg, rgba(255,255,255,.02), rgba(0,0,0,.03));
}
.visually-hidden{position:absolute !important; height:1px; width:1px; overflow:hidden; clip:rect(1px, 1px, 1px, 1px);}
.form{display:grid;gap:12px}
input, textarea{
width:100%;padding:12px 14px;border-radius:14px;border:1px solid var(--line);
background:var(--panel);color:var(--text);outline:none;
transition:border-color .2s ease, box-shadow .25s ease;
}
input:focus, textarea:focus{border-color:transparent;box-shadow:0 0 0 2px rgba(125,211,252,.45)}
button{
padding:11px 14px;border-radius:14px;border:1px solid var(--line);background:
radial-gradient(200% 100% at 0% 0%, rgba(125,211,252,.2), transparent 60%),
radial-gradient(200% 100% at 100% 100%, rgba(244,114,182,.2), transparent 60%),
linear-gradient(180deg, rgba(255,255,255,.02), rgba(0,0,0,.03));
color:var(--text);font-weight:700;cursor:pointer;transition:transform .2s ease, box-shadow .25s ease, border-color .2s ease;
}
button:hover{transform:translateY(-2px);box-shadow:0 14px 28px var(--shadow);border-color:transparent}
.list{display:grid;gap:12px;margin-top:16px}
.item{border:1px solid var(--line);border-radius:14px;padding:14px;background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(0,0,0,.03)), var(--panel)}
.item .meta{font-size:13px;color:var(--muted);display:flex;gap:8px;flex-wrap:wrap}
.item .name{font-weight:700}
.empty{color:var(--muted);text-align:center;padding:16px;border:1px dashed var(--line);border-radius:14px}
.section{margin-top:10px}
</style>
</head>
<body>
<div class="wrap">
<header class="nav">
<div><a class="chip" href="/">← 返回首页</a></div>
<nav class="muted">
<a class="chip" href="/projects.html">Projects</a>
<a class="chip" href="/about.html">About</a>
<a class="chip" href="https://github.com/pinklemon123" target="_blank" rel="noopener">GitHub</a>
</nav>
</header>
<div class="panel" role="region" aria-labelledby="gb-title">
<h1 id="gb-title">Guestbook</h1>
<p class="muted">两种方式留言:<strong>GitHub 登录</strong>(公开,显示在 Discussions)或<strong>本地留言</strong>(仅你自己在本机可见)。</p>
<div class="hr"></div>
<!-- Tabs -->
<div class="tabs" role="tablist" aria-label="留言方式">
<button class="tab-btn" id="tab-giscus" role="tab" aria-selected="true" aria-controls="panel-giscus">GitHub 留言</button>
<button class="tab-btn" id="tab-local" role="tab" aria-selected="false" aria-controls="panel-local">本地留言</button>
</div>
<!-- Panel: Giscus -->
<section id="panel-giscus" class="section" role="tabpanel" aria-labelledby="tab-giscus">
<div id="giscus_container">
<script src="https://giscus.app/client.js"
data-repo="pinklemon123/pinklemon123.github.io"
data-repo-id="R_kgDOPj-aOA"
data-category="lemonの留言板"
data-category-id="DIC_kwDOPj-aOM4Cuk73"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="dark_protanopia"
data-lang="zh-CN"
crossorigin="anonymous"
async>
</script>
<noscript><p class="muted">需要启用 JavaScript 才能加载 Giscus 评论。</p></noscript>
</div>
</section>
<!-- Panel: Local guestbook -->
<section id="panel-local" class="section" role="tabpanel" aria-labelledby="tab-local" hidden>
<p class="muted">本地留言仅存储在你浏览器的 <code>localStorage</code> 中,不会上传到服务器。</p>
<form class="form" id="gb-form" autocomplete="off">
<label class="visually-hidden" for="name">昵称</label>
<input id="name" placeholder="昵称(必填)" required />
<label class="visually-hidden" for="link">个人链接</label>
<input id="link" placeholder="个人链接(可选,例如 GitHub/博客)" />
<label class="visually-hidden" for="msg">留言内容</label>
<textarea id="msg" rows="4" placeholder="留言内容(必填)" required></textarea>
<button type="submit">提交本地留言</button>
</form>
<div class="list" id="gb-list" aria-live="polite"></div>
<p class="empty" id="gb-empty" hidden>还没有本地留言,做第一个吧!</p>
</section>
</div>
</div>
<script>
// --- Tabs ---
const tabG = document.getElementById('tab-giscus');
const tabL = document.getElementById('tab-local');
const panelG = document.getElementById('panel-giscus');
const panelL = document.getElementById('panel-local');
function activate(which){
const isG = which === 'giscus';
tabG.setAttribute('aria-selected', isG ? 'true' : 'false');
tabL.setAttribute('aria-selected', isG ? 'false' : 'true');
panelG.hidden = !isG;
panelL.hidden = isG;
}
tabG.addEventListener('click', ()=>activate('giscus'));
tabL.addEventListener('click', ()=>activate('local'));
// --- Local guestbook (private) ---
const KEY = 'guestbook:pinklemon';
const listEl = document.getElementById('gb-list');
const emptyEl = document.getElementById('gb-empty');
const form = document.getElementById('gb-form');
function loadLocal(){
try{
const arr = JSON.parse(localStorage.getItem(KEY) || '[]');
renderLocal(arr);
}catch(e){
renderLocal([]);
}
}
function saveLocal(arr){
localStorage.setItem(KEY, JSON.stringify(arr));
renderLocal(arr);
}
function escapeHTML(s){return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
function renderLocal(arr){
listEl.innerHTML = '';
if(!arr.length){ emptyEl.hidden = false; return; }
emptyEl.hidden = true;
arr.sort((a,b)=>b.t-a.t).forEach(it=>{
const div = document.createElement('div');
div.className = 'item';
const when = new Date(it.t).toLocaleString();
const link = it.link && it.link.trim() ? ` · <a href="${escapeHTML(it.link)}" target="_blank" rel="noopener">${escapeHTML(it.link)}</a>`:'';
div.innerHTML = `
<div class="meta"><span class="name">${escapeHTML(it.name)}</span> · <span>${when}</span>${link}</div>
<div class="content" style="margin-top:6px">${escapeHTML(it.msg)}</div>
`;
listEl.appendChild(div);
});
}
if (form){
form.addEventListener('submit', (e)=>{
e.preventDefault();
const name = document.getElementById('name').value.trim();
const link = document.getElementById('link').value.trim();
const msg = document.getElementById('msg').value.trim();
if(!name || !msg) return alert('请填写昵称和留言内容');
const arr = JSON.parse(localStorage.getItem(KEY) || '[]');
arr.push({name, link, msg, t: Date.now()});
saveLocal(arr);
form.reset();
});
}
loadLocal();
</script>
</body>
</html>