Skip to content

Commit bd420b5

Browse files
committed
feat: 添加 API 弹窗功能,优化复制链接体验;更新样式和结构
1 parent 7b791ab commit bd420b5

5 files changed

Lines changed: 196 additions & 32 deletions

File tree

public/assets/home.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
function copyText(text, btn) {
2+
var ta = document.createElement('textarea');
3+
ta.value = text;
4+
ta.style.cssText = 'position:fixed;left:-9999px;top:-9999px';
5+
document.body.appendChild(ta);
6+
ta.select();
7+
try {
8+
document.execCommand('copy');
9+
btn.textContent = '已复制';
10+
btn.classList.add('copied');
11+
setTimeout(function() { btn.textContent = '复制'; btn.classList.remove('copied'); }, 1500);
12+
} catch(e) {
13+
btn.textContent = '失败';
14+
}
15+
document.body.removeChild(ta);
16+
}
17+
18+
document.addEventListener('click', function(e) {
19+
var btn = e.target.closest('.copy-btn');
20+
if (!btn) return;
21+
copyText(btn.getAttribute('data-copy'), btn);
22+
});
23+
24+
var modal = document.getElementById('apiModal');
25+
var modalBody = document.getElementById('modalBody');
26+
var modalTitle = document.getElementById('modalTitle');
27+
28+
document.addEventListener('click', function(e) {
29+
var btn = e.target.closest('.api-btn');
30+
if (!btn) return;
31+
var g = btn.getAttribute('data-gallery');
32+
var base = window.location.origin;
33+
modalTitle.textContent = g + ' — API 调用';
34+
var items = [
35+
{ label: '随机图(图片)', path: '/image/api/random?gallery=' + g },
36+
{ label: '随机图(JSON)', path: '/image/api/random?gallery=' + g + '&type=json' },
37+
{ label: '随机图(跳转)', path: '/image/api/random?gallery=' + g + '&type=redirect' },
38+
{ label: 'PC 随机图', path: '/image/api/random?gallery=' + g + '&device=pc' },
39+
{ label: 'Mobile 随机图', path: '/image/api/random?gallery=' + g + '&device=mobile' },
40+
{ label: 'PC JSON', path: '/image/api/random?gallery=' + g + '&device=pc&type=json' },
41+
{ label: 'Mobile JSON', path: '/image/api/random?gallery=' + g + '&device=mobile&type=json' }
42+
];
43+
var html = '';
44+
for (var i = 0; i < items.length; i++) {
45+
var full = base + items[i].path;
46+
html += '<div class="api-row">' +
47+
'<span class="api-label">' + items[i].label + '</span>' +
48+
'<code class="api-url">' + full + '</code>' +
49+
'<button type="button" class="copy-btn" data-copy="' + full + '">复制</button>' +
50+
'</div>';
51+
}
52+
modalBody.innerHTML = html;
53+
modal.hidden = false;
54+
});
55+
56+
document.getElementById('modalClose').addEventListener('click', function() {
57+
modal.hidden = true;
58+
});
59+
60+
modal.addEventListener('click', function(e) {
61+
if (e.target === modal) modal.hidden = true;
62+
});
63+
64+
document.addEventListener('keydown', function(e) {
65+
if (e.key === 'Escape' && !modal.hidden) modal.hidden = true;
66+
});

public/assets/style.css

Lines changed: 114 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -378,50 +378,146 @@ tr:last-child td {
378378
border-bottom: 0;
379379
}
380380

381-
td .api-link {
382-
display: inline-flex;
381+
.api-btn {
382+
min-height: 30px;
383+
padding: 0 10px;
384+
font-size: 0.82rem;
385+
font-weight: 700;
386+
border-radius: 5px;
387+
cursor: pointer;
388+
color: var(--primary);
389+
background: var(--primary-soft);
390+
border: 1px solid transparent;
391+
}
392+
393+
.api-btn:hover {
394+
background: var(--primary);
395+
color: #fff;
396+
}
397+
398+
/* Modal */
399+
.modal-overlay {
400+
position: fixed;
401+
inset: 0;
402+
z-index: 1000;
403+
display: flex;
383404
align-items: center;
384-
gap: 6px;
385-
max-width: 320px;
386-
white-space: nowrap;
405+
justify-content: center;
406+
background: rgba(0, 0, 0, 0.45);
407+
padding: 20px;
408+
}
409+
410+
.modal-overlay[hidden] {
411+
display: none;
412+
}
413+
414+
.modal-box {
415+
width: min(560px, 100%);
416+
max-height: 80vh;
417+
background: var(--surface);
418+
border-radius: 10px;
419+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
420+
display: flex;
421+
flex-direction: column;
387422
overflow: hidden;
388-
text-overflow: ellipsis;
389-
vertical-align: middle;
423+
}
424+
425+
.modal-header {
426+
display: flex;
427+
align-items: center;
428+
justify-content: space-between;
429+
padding: 16px 20px;
430+
border-bottom: 1px solid var(--line);
431+
}
432+
433+
.modal-header h3 {
390434
margin: 0;
391-
padding: 4px 8px;
392-
font-size: 0.82rem;
393-
border-radius: 5px;
435+
font-size: 1.05rem;
394436
}
395437

396-
td .api-link span {
438+
.modal-close {
439+
width: 32px;
440+
height: 32px;
441+
border: none;
442+
background: none;
443+
font-size: 1.4rem;
444+
cursor: pointer;
445+
color: var(--muted);
446+
border-radius: 6px;
447+
}
448+
449+
.modal-close:hover {
450+
background: var(--surface-soft);
451+
color: var(--text);
452+
}
453+
454+
.modal-body {
455+
padding: 16px 20px;
456+
overflow-y: auto;
457+
}
458+
459+
.api-row {
460+
display: grid;
461+
grid-template-columns: 100px 1fr auto;
462+
gap: 10px;
463+
align-items: center;
464+
padding: 10px 0;
465+
border-bottom: 1px solid var(--line);
466+
}
467+
468+
.api-row:last-child {
469+
border-bottom: 0;
470+
}
471+
472+
.api-label {
473+
font-size: 0.85rem;
474+
font-weight: 700;
475+
color: var(--text);
476+
}
477+
478+
.api-url {
397479
overflow: hidden;
398480
text-overflow: ellipsis;
481+
white-space: nowrap;
482+
font-size: 0.82rem;
483+
padding: 4px 8px;
484+
border-radius: 4px;
399485
}
400486

401-
td .copy-btn {
487+
.copy-btn {
402488
flex-shrink: 0;
403-
min-height: 26px;
404-
padding: 0 8px;
405-
font-size: 0.76rem;
489+
min-height: 28px;
490+
padding: 0 10px;
491+
font-size: 0.78rem;
406492
font-weight: 700;
407-
border-radius: 4px;
493+
border-radius: 5px;
408494
cursor: pointer;
409495
color: var(--primary);
410496
background: var(--primary-soft);
411497
border: 1px solid transparent;
412498
}
413499

414-
td .copy-btn:hover {
500+
.copy-btn:hover {
415501
background: var(--primary);
416502
color: #fff;
417503
}
418504

419-
td .copy-btn.copied {
505+
.copy-btn.copied {
420506
color: var(--success);
421507
background: var(--teal-soft);
422508
pointer-events: none;
423509
}
424510

511+
@media (max-width: 520px) {
512+
.api-row {
513+
grid-template-columns: 1fr;
514+
gap: 6px;
515+
}
516+
.api-label {
517+
font-size: 0.8rem;
518+
}
519+
}
520+
425521
code {
426522
display: block;
427523
width: 100%;

src/routes/publicRoutes.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ function galleryRows(galleries) {
2727
const nameCell = gallery.label
2828
? `${escapeHtml(displayName)}<br><span class="muted">${escapeHtml(gallery.name)}</span>`
2929
: escapeHtml(displayName);
30-
const apiUrl = `/image/api/random?gallery=${encodeURIComponent(gallery.name)}`;
30+
const g = escapeHtml(gallery.name);
3131
return `<tr>
3232
<td>${nameCell}</td>
3333
<td>${gallery.total}</td>
3434
<td>${gallery.pc}</td>
3535
<td>${gallery.mobile}</td>
36-
<td><code class="api-link"><span>${escapeHtml(apiUrl)}</span> <button type="button" class="copy-btn" data-copy="${escapeHtml(apiUrl)}" title="复制">复制</button></code></td>
36+
<td><button type="button" class="api-btn" data-gallery="${g}">查看 API</button></td>
3737
</tr>`;
3838
}
3939
)

views/admin-dashboard.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ <h1>随机图后台</h1>
5757
{{message}}
5858

5959
<nav class="admin-nav" aria-label="后台分区">
60+
<a href="/image/">← 首页</a>
6061
<a href="#upload">上传</a>
6162
<a href="#images">图片管理</a>
6263
<a href="#galleries">图库</a>

views/index.html

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,18 @@ <h2>API 调用示例</h2>
7979
</article>
8080
</section>
8181
</main>
82-
<script>
83-
document.addEventListener('click', async (e) => {
84-
const btn = e.target.closest('.copy-btn');
85-
if (!btn) return;
86-
try {
87-
await navigator.clipboard.writeText(btn.dataset.copy);
88-
btn.textContent = '已复制';
89-
btn.classList.add('copied');
90-
setTimeout(() => { btn.textContent = '复制'; btn.classList.remove('copied'); }, 1500);
91-
} catch { btn.textContent = '失败'; }
92-
});
93-
</script>
82+
83+
<!-- API 弹窗 -->
84+
<div id="apiModal" class="modal-overlay" hidden>
85+
<div class="modal-box">
86+
<div class="modal-header">
87+
<h3 id="modalTitle">API 调用</h3>
88+
<button type="button" class="modal-close" id="modalClose">&times;</button>
89+
</div>
90+
<div class="modal-body" id="modalBody"></div>
91+
</div>
92+
</div>
93+
94+
<script src="/image/assets/home.js"></script>
9495
</body>
9596
</html>

0 commit comments

Comments
 (0)