v0.4.0: 重做图库为瀑布流+分组导航,修复豆瓣 500 与瞬间样式,友链卡片重排+申请弹窗,标签云间距,移除关于模板
This commit is contained in:
+176
-48
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user