v0.4.0: 重做图库为瀑布流+分组导航,修复豆瓣 500 与瞬间样式,友链卡片重排+申请弹窗,标签云间距,移除关于模板

This commit is contained in:
2026-09-30 13:32:54 +08:00
parent 5e50c01c18
commit 5ad34cf233
13 changed files with 455 additions and 559 deletions
+176 -48
View File
@@ -31,37 +31,61 @@
.links-list a {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 1rem;
gap: 0.8rem;
padding: 1.1rem 1.25rem;
width: 100%;
box-sizing: border-box;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
border-radius: var(--radius-lg, 0.75rem);
background: var(--color-bg-secondary);
color: var(--color-text);
transition: border-color var(--transition-fast);
transition:
border-color var(--transition-fast),
box-shadow var(--transition-fast);
}
.links-list a:hover {
border-color: var(--color-primary);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.links-list img {
width: 2.5rem;
height: 2.5rem;
border-radius: var(--radius-sm);
object-fit: cover;
.links-avatar {
position: relative;
display: block;
flex-shrink: 0;
}
.links-avatar img {
display: block;
width: 2.75rem;
height: 2.75rem;
border-radius: var(--radius-md);
object-fit: cover;
background: var(--color-bg);
}
/* 头像右下角状态圆点 */
.links-avatar::after {
content: "";
position: absolute;
right: -0.1rem;
bottom: -0.1rem;
width: 0.55rem;
height: 0.55rem;
border-radius: 50%;
background: #2ea043;
border: 2px solid var(--color-bg-secondary);
}
.links-list .links-body {
display: flex;
flex-direction: column;
min-width: 0;
padding-top: 0.1rem;
}
.links-list .links-name {
font-weight: 600;
line-height: 1.4;
}
.links-list .links-desc {
margin: 0.25rem 0 0;
margin: 0.3rem 0 0;
font-size: 0.85rem;
line-height: 1.55;
color: var(--color-text-secondary);
display: -webkit-box;
-webkit-line-clamp: 2;
@@ -77,18 +101,79 @@
.links-section:first-of-type .links-group-title {
margin-top: 0;
}
/* 申请友链按钮 */
.links-apply {
margin-top: 2rem;
margin-top: 2.5rem;
text-align: center;
}
.link-apply-panel {
max-width: 32rem;
margin: 1.25rem auto 0;
text-align: left;
.btn-apply {
display: inline-block;
padding: 0.6rem 1.75rem;
border: 1px solid var(--color-primary);
border-radius: var(--radius-full);
background: var(--color-primary);
color: #fff;
font: inherit;
font-size: 0.95rem;
cursor: pointer;
transition:
opacity var(--transition-fast),
transform var(--transition-fast);
}
.btn-apply:hover {
opacity: 0.88;
}
.btn-apply:active {
transform: scale(0.97);
}
/* 申请弹窗(运行时移至 body 下,避免被父级 stacking context 遮挡) */
.link-apply-modal[hidden] {
display: none;
}
.link-apply-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1000;
}
.link-apply-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: min(26rem, calc(100vw - 2rem));
max-height: min(85vh, 44rem);
overflow-y: auto;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg, 0.75rem);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
padding: 1.5rem;
z-index: 1001;
}
.link-apply-close {
position: absolute;
top: 0.75rem;
right: 0.75rem;
width: 2rem;
height: 2rem;
border: none;
border-radius: 50%;
background: transparent;
color: var(--color-text-muted);
font-size: 1.4rem;
line-height: 1;
cursor: pointer;
}
.link-apply-close:hover {
color: var(--color-text);
background: var(--color-bg-secondary);
}
.link-apply-title {
margin: 0 0 0.75rem;
margin: 0 0 1rem;
font-size: 1.125rem;
padding-right: 2rem;
}
.apply-form .form-row {
margin-bottom: 1rem;
@@ -174,12 +259,14 @@
target="_blank"
rel="noopener noreferrer"
>
<img
th:if="${not #strings.isEmpty(link.spec.logo)}"
th:src="@{${link.spec.logo}}"
alt=""
loading="lazy"
/>
<span class="links-avatar">
<img
th:if="${not #strings.isEmpty(link.spec.logo)}"
th:src="@{${link.spec.logo}}"
alt=""
loading="lazy"
/>
</span>
<span class="links-body">
<span class="links-name" th:text="${link.spec.displayName}"
>链接名称</span
@@ -206,12 +293,14 @@
target="_blank"
rel="noopener noreferrer"
>
<img
th:if="${not #strings.isEmpty(link.spec.logo)}"
th:src="@{${link.spec.logo}}"
alt=""
loading="lazy"
/>
<span class="links-avatar">
<img
th:if="${not #strings.isEmpty(link.spec.logo)}"
th:src="@{${link.spec.logo}}"
alt=""
loading="lazy"
/>
</span>
<span class="links-body">
<span class="links-name" th:text="${link.spec.displayName}"
>链接名称</span
@@ -235,12 +324,14 @@
target="_blank"
rel="noopener noreferrer"
>
<img
th:if="${not #strings.isEmpty(link.spec.logo)}"
th:src="@{${link.spec.logo}}"
alt=""
loading="lazy"
/>
<span class="links-avatar">
<img
th:if="${not #strings.isEmpty(link.spec.logo)}"
th:src="@{${link.spec.logo}}"
alt=""
loading="lazy"
/>
</span>
<span class="links-body">
<span class="links-name" th:text="${link.spec.displayName}"
>链接名称</span
@@ -259,14 +350,35 @@
<div class="links-apply">
<button
class="btn btn-primary"
class="btn-apply"
id="link-apply-toggle"
type="button"
th:text="#{links.apply}"
>申请友链</button>
<div class="link-apply-panel apply-form" id="link-apply-panel" hidden>
<h2 class="link-apply-title" th:text="#{links.apply}">申请友链</h2>
<form id="link-apply-form" novalidate>
</div>
</section>
<!-- 申请友链弹窗:脚本运行时移至 body 下 -->
<div class="link-apply-modal" id="link-apply-modal" hidden>
<div class="link-apply-backdrop" data-close></div>
<div
class="link-apply-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="link-apply-title"
>
<button
class="link-apply-close"
type="button"
data-close
aria-label="关闭"
>
×
</button>
<h2 class="link-apply-title" id="link-apply-title" th:text="#{links.apply}">
申请友链
</h2>
<form class="apply-form" id="link-apply-form" novalidate>
<div class="form-row">
<label for="f-url">网站地址 *</label>
<input id="f-url" name="url" type="url" required placeholder="https://example.com" />
@@ -302,12 +414,11 @@
<input id="f-captcha" name="captchaCode" type="text" maxlength="5" required autocomplete="off" />
</div>
</div>
<button class="btn btn-primary" type="submit">提交申请</button>
<button class="btn-apply" type="submit">提交申请</button>
</form>
<div class="apply-status" id="apply-status" role="alert"></div>
</div>
</div>
</section>
<div class="comments-section" th:if="${haloCommentEnabled}">
<halo:comment group="plugin.halo.run" kind="Plugin" th:attr="name=${pluginName}" />
@@ -326,12 +437,35 @@
var API = "/apis/api.link.halo.run/v1alpha1/link-applications";
var CAPTCHA = "/apis/api.link.halo.run/v1alpha1/link-applications/captcha";
var toggle = document.getElementById("link-apply-toggle");
var panel = document.getElementById("link-apply-panel");
var modal = document.getElementById("link-apply-modal");
var form = document.getElementById("link-apply-form");
var img = document.getElementById("captcha-img");
var status = document.getElementById("apply-status");
var challengeId = null;
// 弹窗移至 body 下,避免被页面父级 stacking context 遮挡
document.body.appendChild(modal);
function openModal() {
modal.hidden = false;
document.body.style.overflow = "hidden";
if (!challengeId) loadCaptcha();
}
function closeModal() {
modal.hidden = true;
document.body.style.overflow = "";
}
toggle.addEventListener("click", openModal);
modal.addEventListener("click", function (e) {
if (e.target.closest("[data-close]")) closeModal();
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && !modal.hidden) closeModal();
});
function loadCaptcha() {
fetch(CAPTCHA, { method: "POST" })
.then(function (r) {
@@ -348,13 +482,6 @@
});
}
toggle.addEventListener("click", function () {
panel.hidden = !panel.hidden;
if (!panel.hidden && !challengeId) {
loadCaptcha();
}
});
img.addEventListener("click", loadCaptcha);
form.addEventListener("submit", function (e) {
@@ -394,6 +521,7 @@
loadCaptcha();
status.className = "apply-status ok";
status.textContent = "申请已提交,等待管理员审核。";
setTimeout(closeModal, 1500);
} else {
return r.json().then(function (err) {
throw err;