@windcoder/astro-theme-orchid 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/i18n/en.ts +8 -0
- package/src/i18n/ja.ts +8 -0
- package/src/i18n/ko.ts +8 -0
- package/src/i18n/ru.ts +8 -0
- package/src/i18n/zh-CN.ts +8 -0
- package/src/i18n/zh-TW.ts +8 -0
- package/src/routes/friends.astro +399 -19
- package/src/schema.ts +74 -2
- package/src/styles/global.css +317 -1
package/package.json
CHANGED
package/src/i18n/en.ts
CHANGED
|
@@ -78,6 +78,14 @@ const en: Record<UiKey, string> = {
|
|
|
78
78
|
avatarAlt: "Avatar of {name}",
|
|
79
79
|
noFriends: "No friend links yet",
|
|
80
80
|
applyFriend: "Apply for a link",
|
|
81
|
+
friendSearch: "Search links…",
|
|
82
|
+
friendAll: "All",
|
|
83
|
+
noFriendMatch: "No matching links",
|
|
84
|
+
copy: "Copy",
|
|
85
|
+
friendSiteName: "Site name",
|
|
86
|
+
friendSiteDesc: "Site description",
|
|
87
|
+
friendSiteUrl: "Site URL",
|
|
88
|
+
friendAvatarUrl: "Avatar URL",
|
|
81
89
|
/* Bangumi watching page (§4.93) */
|
|
82
90
|
bangumiEmpty: "Nothing being watched yet",
|
|
83
91
|
bangumiFail: "Failed to fetch Bangumi data. Rebuild the site to retry.",
|
package/src/i18n/ja.ts
CHANGED
|
@@ -78,6 +78,14 @@ const ja: Record<UiKey, string> = {
|
|
|
78
78
|
avatarAlt: "{name} のアバター",
|
|
79
79
|
noFriends: "リンクはまだありません",
|
|
80
80
|
applyFriend: "リンク申請",
|
|
81
|
+
friendSearch: "リンクを検索…",
|
|
82
|
+
friendAll: "すべて",
|
|
83
|
+
noFriendMatch: "該当するリンクがありません",
|
|
84
|
+
copy: "コピー",
|
|
85
|
+
friendSiteName: "サイト名",
|
|
86
|
+
friendSiteDesc: "サイト説明",
|
|
87
|
+
friendSiteUrl: "サイトURL",
|
|
88
|
+
friendAvatarUrl: "アバターURL",
|
|
81
89
|
/* 番組視聴ページ */
|
|
82
90
|
bangumiEmpty: "視聴中の番組はまだありません",
|
|
83
91
|
bangumiFail:
|
package/src/i18n/ko.ts
CHANGED
|
@@ -77,6 +77,14 @@ const ko: Record<UiKey, string> = {
|
|
|
77
77
|
avatarAlt: "{name}의 아바타",
|
|
78
78
|
noFriends: "아직 링크가 없습니다",
|
|
79
79
|
applyFriend: "링크 신청",
|
|
80
|
+
friendSearch: "링크 검색…",
|
|
81
|
+
friendAll: "전체",
|
|
82
|
+
noFriendMatch: "일치하는 링크가 없습니다",
|
|
83
|
+
copy: "복사",
|
|
84
|
+
friendSiteName: "사이트 이름",
|
|
85
|
+
friendSiteDesc: "사이트 설명",
|
|
86
|
+
friendSiteUrl: "사이트 URL",
|
|
87
|
+
friendAvatarUrl: "아바타 URL",
|
|
80
88
|
/* 애니 시청 페이지 */
|
|
81
89
|
bangumiEmpty: "시청 중인 애니메이션이 없습니다",
|
|
82
90
|
bangumiFail:
|
package/src/i18n/ru.ts
CHANGED
|
@@ -77,6 +77,14 @@ const ru: Record<UiKey, string> = {
|
|
|
77
77
|
avatarAlt: "Аватар {name}",
|
|
78
78
|
noFriends: "Ссылок пока нет",
|
|
79
79
|
applyFriend: "Заявка на обмен ссылками",
|
|
80
|
+
friendSearch: "Поиск ссылок…",
|
|
81
|
+
friendAll: "Все",
|
|
82
|
+
noFriendMatch: "Ничего не найдено",
|
|
83
|
+
copy: "Копировать",
|
|
84
|
+
friendSiteName: "Название сайта",
|
|
85
|
+
friendSiteDesc: "Описание сайта",
|
|
86
|
+
friendSiteUrl: "Ссылка на сайт",
|
|
87
|
+
friendAvatarUrl: "Ссылка на аватар",
|
|
80
88
|
/* Страница отслеживания аниме */
|
|
81
89
|
bangumiEmpty: "Пока ничего не смотрю",
|
|
82
90
|
bangumiFail:
|
package/src/i18n/zh-CN.ts
CHANGED
|
@@ -91,6 +91,14 @@ const zhCN = {
|
|
|
91
91
|
avatarAlt: "{name} 的头像",
|
|
92
92
|
noFriends: "还没有友链",
|
|
93
93
|
applyFriend: "申请友链",
|
|
94
|
+
friendSearch: "搜索友链…",
|
|
95
|
+
friendAll: "全部",
|
|
96
|
+
noFriendMatch: "没有匹配的友链",
|
|
97
|
+
copy: "复制",
|
|
98
|
+
friendSiteName: "站点名称",
|
|
99
|
+
friendSiteDesc: "站点描述",
|
|
100
|
+
friendSiteUrl: "站点链接",
|
|
101
|
+
friendAvatarUrl: "头像链接",
|
|
94
102
|
/* 番组追番页(§4.93) */
|
|
95
103
|
bangumiEmpty: "还没有在看中的番剧",
|
|
96
104
|
bangumiFail: "番组数据拉取失败,请重新构建站点后重试",
|
package/src/i18n/zh-TW.ts
CHANGED
|
@@ -77,6 +77,14 @@ const zhTW: Record<UiKey, string> = {
|
|
|
77
77
|
avatarAlt: "{name} 的頭像",
|
|
78
78
|
noFriends: "還沒有友鏈",
|
|
79
79
|
applyFriend: "申請友鏈",
|
|
80
|
+
friendSearch: "搜尋友鏈…",
|
|
81
|
+
friendAll: "全部",
|
|
82
|
+
noFriendMatch: "沒有符合的友鏈",
|
|
83
|
+
copy: "複製",
|
|
84
|
+
friendSiteName: "站點名稱",
|
|
85
|
+
friendSiteDesc: "站點描述",
|
|
86
|
+
friendSiteUrl: "站點連結",
|
|
87
|
+
friendAvatarUrl: "頭像連結",
|
|
80
88
|
/* 番組追番頁 */
|
|
81
89
|
bangumiEmpty: "還沒有在看中的番劇",
|
|
82
90
|
bangumiFail: "番組資料拉取失敗,請重新建置網站後重試",
|
package/src/routes/friends.astro
CHANGED
|
@@ -22,19 +22,47 @@ const friendImgs = await Promise.all(
|
|
|
22
22
|
),
|
|
23
23
|
);
|
|
24
24
|
|
|
25
|
-
// 可选 spec 正文(src/content/spec/friends.md
|
|
25
|
+
// 可选 spec 正文(src/content/spec/friends.md),渲染在区块卡上方
|
|
26
26
|
const entry = await getEntry("spec", "friends").catch(() => null);
|
|
27
27
|
const { Content } = entry ? await render(entry) : { Content: null };
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const friendsCfg = config.friends;
|
|
30
|
+
const apply = friendsCfg.apply;
|
|
31
|
+
const siteInfo = friendsCfg.siteInfo;
|
|
32
|
+
const notice = friendsCfg.notice;
|
|
33
|
+
|
|
34
|
+
// 分组 pills:由 list tags 聚合去重(保持首次出现顺序),无 tags 自动隐藏
|
|
35
|
+
const groupTags = [...new Set(friends.flatMap((f) => f.tags))].filter(Boolean);
|
|
36
|
+
const showGroups = friendsCfg.filter.groups && groupTags.length > 0;
|
|
37
|
+
const showSearch = friendsCfg.filter.search;
|
|
38
|
+
|
|
39
|
+
// 本站信息卡:name/desc/site/avatar 任一非空才渲染
|
|
40
|
+
const siteInfoRows = (
|
|
41
|
+
[
|
|
42
|
+
[t("friendSiteName"), siteInfo.name],
|
|
43
|
+
[t("friendSiteDesc"), siteInfo.desc],
|
|
44
|
+
[t("friendSiteUrl"), siteInfo.site],
|
|
45
|
+
[t("friendAvatarUrl"), siteInfo.avatar],
|
|
46
|
+
] as [string, string][]
|
|
47
|
+
).filter(([, v]) => v);
|
|
48
|
+
const hasSiteInfo = siteInfoRows.length > 0;
|
|
49
|
+
// 本站头像三格式解析(§4.97),空串跳过用字头像兜底
|
|
50
|
+
const siteAvatar = siteInfo.avatar
|
|
51
|
+
? await resolveSiteImage(siteInfo.avatar)
|
|
52
|
+
: "";
|
|
53
|
+
|
|
54
|
+
// 申请模板整块复制文本:label: value 每行一条(模板块右上角一键复制)
|
|
55
|
+
const applyTemplateText = apply.template
|
|
56
|
+
.map((r) => `${r.label}: ${r.value}`)
|
|
57
|
+
.join("\n");
|
|
31
58
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
// 申请卡:有步骤或模板时渲染富卡(与站点信息并排);否则回退旧的横向申请条
|
|
60
|
+
const hasApplyRich = Boolean(
|
|
61
|
+
apply.title && (apply.steps.length > 0 || apply.template.length > 0),
|
|
62
|
+
);
|
|
63
|
+
---
|
|
37
64
|
|
|
65
|
+
<BaseLayout title={friendsCfg.title} page="friends">
|
|
38
66
|
{
|
|
39
67
|
Content && (
|
|
40
68
|
<article class="card page-card prose reveal" data-lightbox-gallery>
|
|
@@ -43,14 +71,87 @@ const apply = config.friends.apply;
|
|
|
43
71
|
)
|
|
44
72
|
}
|
|
45
73
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<div class="friend-
|
|
49
|
-
|
|
50
|
-
|
|
74
|
+
<section class="friend-zone card reveal" data-friend-zone>
|
|
75
|
+
<div class="friend-toolbar">
|
|
76
|
+
<div class="friend-zone-title">
|
|
77
|
+
<svg
|
|
78
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
79
|
+
viewBox="0 0 24 24"
|
|
80
|
+
fill="none"
|
|
81
|
+
stroke="currentColor"
|
|
82
|
+
stroke-width="2"
|
|
83
|
+
stroke-linecap="round"
|
|
84
|
+
stroke-linejoin="round"
|
|
85
|
+
aria-hidden="true"
|
|
86
|
+
>
|
|
87
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
88
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
89
|
+
</svg>
|
|
90
|
+
<span>{friendsCfg.title}</span>
|
|
91
|
+
</div>
|
|
92
|
+
{
|
|
93
|
+
showSearch && (
|
|
94
|
+
<div class="friend-search">
|
|
95
|
+
<svg
|
|
96
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
97
|
+
viewBox="0 0 24 24"
|
|
98
|
+
fill="none"
|
|
99
|
+
stroke="currentColor"
|
|
100
|
+
stroke-width="2"
|
|
101
|
+
stroke-linecap="round"
|
|
102
|
+
stroke-linejoin="round"
|
|
103
|
+
aria-hidden="true"
|
|
104
|
+
>
|
|
105
|
+
<circle cx="11" cy="11" r="8" />
|
|
106
|
+
<path d="m21 21-4.3-4.3" />
|
|
107
|
+
</svg>
|
|
108
|
+
<input
|
|
109
|
+
type="search"
|
|
110
|
+
placeholder={t("friendSearch")}
|
|
111
|
+
aria-label={t("friendSearch")}
|
|
112
|
+
data-friend-search
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
</div>
|
|
118
|
+
{friendsCfg.description && <p class="friend-zone-desc">{friendsCfg.description}</p>}
|
|
119
|
+
{
|
|
120
|
+
showGroups && (
|
|
121
|
+
<div class="friend-pills" role="group" aria-label={t("friendAll")}>
|
|
122
|
+
<button type="button" class="chip is-on" data-friend-pill="">
|
|
123
|
+
{t("friendAll")}
|
|
124
|
+
</button>
|
|
125
|
+
{groupTags.map((gt) => (
|
|
126
|
+
<button type="button" class="chip" data-friend-pill={gt}>
|
|
127
|
+
{gt}
|
|
128
|
+
</button>
|
|
129
|
+
))}
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
<div class="friend-grid">
|
|
134
|
+
{
|
|
135
|
+
friends.map((f, i) => (
|
|
136
|
+
<a
|
|
137
|
+
class="friend-card card"
|
|
138
|
+
href={f.site}
|
|
139
|
+
target="_blank"
|
|
140
|
+
rel="noopener"
|
|
141
|
+
data-friend-card
|
|
142
|
+
data-search={[f.title, f.desc, ...f.tags]
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
.join(" ")
|
|
145
|
+
.toLowerCase()}
|
|
146
|
+
data-tags={JSON.stringify(f.tags)}
|
|
147
|
+
>
|
|
51
148
|
<div class="friend-avatar">
|
|
52
149
|
{f.image ? (
|
|
53
|
-
<img
|
|
150
|
+
<img
|
|
151
|
+
src={friendImgs[i]}
|
|
152
|
+
alt={t("avatarAlt", { name: f.title })}
|
|
153
|
+
loading="lazy"
|
|
154
|
+
/>
|
|
54
155
|
) : (
|
|
55
156
|
<span class="avatar-fallback">{f.title.slice(0, 1)}</span>
|
|
56
157
|
)}
|
|
@@ -67,15 +168,191 @@ const apply = config.friends.apply;
|
|
|
67
168
|
)}
|
|
68
169
|
</div>
|
|
69
170
|
</a>
|
|
70
|
-
))
|
|
171
|
+
))
|
|
172
|
+
}
|
|
173
|
+
</div>
|
|
174
|
+
<p class="tag-empty" data-friend-empty hidden>
|
|
175
|
+
{t("noFriendMatch")}
|
|
176
|
+
</p>
|
|
177
|
+
</section>
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
(hasSiteInfo || hasApplyRich) && (
|
|
181
|
+
<div class="friend-duo">
|
|
182
|
+
{hasSiteInfo && (
|
|
183
|
+
<section class="friend-siteinfo card reveal">
|
|
184
|
+
<div class="friend-card-title">
|
|
185
|
+
<svg
|
|
186
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
187
|
+
viewBox="0 0 24 24"
|
|
188
|
+
fill="none"
|
|
189
|
+
stroke="currentColor"
|
|
190
|
+
stroke-width="2"
|
|
191
|
+
stroke-linecap="round"
|
|
192
|
+
stroke-linejoin="round"
|
|
193
|
+
aria-hidden="true"
|
|
194
|
+
>
|
|
195
|
+
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
|
196
|
+
<polyline points="9 22 9 12 15 12 15 22" />
|
|
197
|
+
</svg>
|
|
198
|
+
<span>{siteInfo.title}</span>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="siteinfo-head">
|
|
201
|
+
<div
|
|
202
|
+
class="siteinfo-avatar"
|
|
203
|
+
data-siteinfo-avatar
|
|
204
|
+
data-avatar-name={siteInfo.name}
|
|
205
|
+
>
|
|
206
|
+
{siteAvatar ? (
|
|
207
|
+
<img src={siteAvatar} alt={siteInfo.name} loading="lazy" />
|
|
208
|
+
) : (
|
|
209
|
+
<span class="avatar-fallback">
|
|
210
|
+
{(siteInfo.name || "?").slice(0, 1)}
|
|
211
|
+
</span>
|
|
212
|
+
)}
|
|
213
|
+
</div>
|
|
214
|
+
<div class="siteinfo-meta">
|
|
215
|
+
<div class="siteinfo-name">{siteInfo.name}</div>
|
|
216
|
+
{siteInfo.desc && <p class="siteinfo-desc">{siteInfo.desc}</p>}
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
{siteInfoRows.map(([label, value]) => (
|
|
220
|
+
<div class="kv-row">
|
|
221
|
+
<div class="kv-main">
|
|
222
|
+
<span class="kv-label">{label}</span>
|
|
223
|
+
<span class="kv-value">{value}</span>
|
|
224
|
+
</div>
|
|
225
|
+
<button
|
|
226
|
+
type="button"
|
|
227
|
+
class="copy-btn"
|
|
228
|
+
data-copy={value}
|
|
229
|
+
aria-label={t("copy")}
|
|
230
|
+
title={t("copy")}
|
|
231
|
+
>
|
|
232
|
+
<svg
|
|
233
|
+
class="icon-copy"
|
|
234
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
235
|
+
viewBox="0 0 24 24"
|
|
236
|
+
fill="none"
|
|
237
|
+
stroke="currentColor"
|
|
238
|
+
stroke-width="2"
|
|
239
|
+
stroke-linecap="round"
|
|
240
|
+
stroke-linejoin="round"
|
|
241
|
+
aria-hidden="true"
|
|
242
|
+
>
|
|
243
|
+
<rect width="14" height="14" x="8" y="8" rx="2" />
|
|
244
|
+
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
|
|
245
|
+
</svg>
|
|
246
|
+
<svg
|
|
247
|
+
class="icon-check"
|
|
248
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
249
|
+
viewBox="0 0 24 24"
|
|
250
|
+
fill="none"
|
|
251
|
+
stroke="currentColor"
|
|
252
|
+
stroke-width="2"
|
|
253
|
+
stroke-linecap="round"
|
|
254
|
+
stroke-linejoin="round"
|
|
255
|
+
aria-hidden="true"
|
|
256
|
+
>
|
|
257
|
+
<path d="M20 6 9 17l-5-5" />
|
|
258
|
+
</svg>
|
|
259
|
+
</button>
|
|
260
|
+
</div>
|
|
261
|
+
))}
|
|
262
|
+
</section>
|
|
263
|
+
)}
|
|
264
|
+
{hasApplyRich && (
|
|
265
|
+
<section class="friend-apply-card card reveal">
|
|
266
|
+
<div class="friend-card-title">
|
|
267
|
+
<svg
|
|
268
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
269
|
+
viewBox="0 0 24 24"
|
|
270
|
+
fill="none"
|
|
271
|
+
stroke="currentColor"
|
|
272
|
+
stroke-width="2"
|
|
273
|
+
stroke-linecap="round"
|
|
274
|
+
stroke-linejoin="round"
|
|
275
|
+
aria-hidden="true"
|
|
276
|
+
>
|
|
277
|
+
<rect width="20" height="16" x="2" y="4" rx="2" />
|
|
278
|
+
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
|
279
|
+
</svg>
|
|
280
|
+
<span>{apply.title}</span>
|
|
281
|
+
</div>
|
|
282
|
+
{apply.description && <p class="fa-desc">{apply.description}</p>}
|
|
283
|
+
{apply.steps.length > 0 && (
|
|
284
|
+
<ol class="apply-steps">
|
|
285
|
+
{apply.steps.map((s, i) => (
|
|
286
|
+
<li class="apply-step">
|
|
287
|
+
<span class="apply-step-num">{i + 1}</span>
|
|
288
|
+
<div>
|
|
289
|
+
<div class="apply-step-title">{s.title}</div>
|
|
290
|
+
{s.description && <p class="apply-step-desc">{s.description}</p>}
|
|
291
|
+
</div>
|
|
292
|
+
</li>
|
|
293
|
+
))}
|
|
294
|
+
</ol>
|
|
295
|
+
)}
|
|
296
|
+
{apply.template.length > 0 && (
|
|
297
|
+
<div class="apply-template">
|
|
298
|
+
<button
|
|
299
|
+
type="button"
|
|
300
|
+
class="copy-btn"
|
|
301
|
+
data-copy={applyTemplateText}
|
|
302
|
+
aria-label={t("copy")}
|
|
303
|
+
title={t("copy")}
|
|
304
|
+
>
|
|
305
|
+
<svg
|
|
306
|
+
class="icon-copy"
|
|
307
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
308
|
+
viewBox="0 0 24 24"
|
|
309
|
+
fill="none"
|
|
310
|
+
stroke="currentColor"
|
|
311
|
+
stroke-width="2"
|
|
312
|
+
stroke-linecap="round"
|
|
313
|
+
stroke-linejoin="round"
|
|
314
|
+
aria-hidden="true"
|
|
315
|
+
>
|
|
316
|
+
<rect width="14" height="14" x="8" y="8" rx="2" />
|
|
317
|
+
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
|
|
318
|
+
</svg>
|
|
319
|
+
<svg
|
|
320
|
+
class="icon-check"
|
|
321
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
322
|
+
viewBox="0 0 24 24"
|
|
323
|
+
fill="none"
|
|
324
|
+
stroke="currentColor"
|
|
325
|
+
stroke-width="2"
|
|
326
|
+
stroke-linecap="round"
|
|
327
|
+
stroke-linejoin="round"
|
|
328
|
+
aria-hidden="true"
|
|
329
|
+
>
|
|
330
|
+
<path d="M20 6 9 17l-5-5" />
|
|
331
|
+
</svg>
|
|
332
|
+
</button>
|
|
333
|
+
<div class="apply-template-text">
|
|
334
|
+
{apply.template.map((row) => (
|
|
335
|
+
<div class="apply-template-line">
|
|
336
|
+
{row.label}: {row.value}
|
|
337
|
+
</div>
|
|
338
|
+
))}
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
)}
|
|
342
|
+
{apply.link && (
|
|
343
|
+
<a class="btn" href={apply.link}>
|
|
344
|
+
{apply.label || t("applyFriend")}
|
|
345
|
+
</a>
|
|
346
|
+
)}
|
|
347
|
+
</section>
|
|
348
|
+
)}
|
|
71
349
|
</div>
|
|
72
|
-
) : (
|
|
73
|
-
<p class="tag-empty reveal">{t('noFriends')}</p>
|
|
74
350
|
)
|
|
75
351
|
}
|
|
76
352
|
|
|
77
353
|
{
|
|
78
|
-
|
|
354
|
+
// 兼容旧配置:无步骤无模板时保留原横向申请条
|
|
355
|
+
apply.title && !hasApplyRich && (
|
|
79
356
|
<section class="friend-apply card reveal">
|
|
80
357
|
<div>
|
|
81
358
|
<div class="fa-title">{apply.title}</div>
|
|
@@ -83,13 +360,116 @@ const apply = config.friends.apply;
|
|
|
83
360
|
</div>
|
|
84
361
|
{apply.link && (
|
|
85
362
|
<a class="btn" href={apply.link}>
|
|
86
|
-
{apply.label || t(
|
|
363
|
+
{apply.label || t("applyFriend")}
|
|
87
364
|
</a>
|
|
88
365
|
)}
|
|
89
366
|
</section>
|
|
90
367
|
)
|
|
91
368
|
}
|
|
92
369
|
|
|
370
|
+
{
|
|
371
|
+
notice.items.length > 0 && (
|
|
372
|
+
<section class="friend-notice card reveal">
|
|
373
|
+
<div class="friend-card-title">
|
|
374
|
+
<svg
|
|
375
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
376
|
+
viewBox="0 0 24 24"
|
|
377
|
+
fill="none"
|
|
378
|
+
stroke="currentColor"
|
|
379
|
+
stroke-width="2"
|
|
380
|
+
stroke-linecap="round"
|
|
381
|
+
stroke-linejoin="round"
|
|
382
|
+
aria-hidden="true"
|
|
383
|
+
>
|
|
384
|
+
<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
|
|
385
|
+
<path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" />
|
|
386
|
+
</svg>
|
|
387
|
+
<span>{notice.title}</span>
|
|
388
|
+
</div>
|
|
389
|
+
<dl class="notice-list">
|
|
390
|
+
{notice.items.map((item) => (
|
|
391
|
+
<div class="notice-item">
|
|
392
|
+
<dt>{item.term}</dt>
|
|
393
|
+
{item.description && <dd>{item.description}</dd>}
|
|
394
|
+
</div>
|
|
395
|
+
))}
|
|
396
|
+
</dl>
|
|
397
|
+
</section>
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
|
|
93
401
|
<!-- §4.113:友链页评论区,支持直接留言申请友链(provider 未启用时自动 no-op) -->
|
|
94
402
|
<Comment path="/friends" />
|
|
95
403
|
</BaseLayout>
|
|
404
|
+
|
|
405
|
+
<script>
|
|
406
|
+
// 友链区块卡:搜索 + 分组 pills 叠加过滤
|
|
407
|
+
const zone = document.querySelector<HTMLElement>("[data-friend-zone]");
|
|
408
|
+
if (zone) {
|
|
409
|
+
const search = zone.querySelector<HTMLInputElement>("[data-friend-search]");
|
|
410
|
+
const pills = Array.from(
|
|
411
|
+
zone.querySelectorAll<HTMLButtonElement>("[data-friend-pill]"),
|
|
412
|
+
);
|
|
413
|
+
const cards = Array.from(
|
|
414
|
+
zone.querySelectorAll<HTMLElement>("[data-friend-card]"),
|
|
415
|
+
);
|
|
416
|
+
const empty = zone.querySelector<HTMLElement>("[data-friend-empty]");
|
|
417
|
+
let keyword = "";
|
|
418
|
+
let group = "";
|
|
419
|
+
const applyFilter = () => {
|
|
420
|
+
let visible = 0;
|
|
421
|
+
for (const card of cards) {
|
|
422
|
+
const okKeyword =
|
|
423
|
+
!keyword || (card.dataset.search || "").includes(keyword);
|
|
424
|
+
let tags: string[] = [];
|
|
425
|
+
try {
|
|
426
|
+
tags = JSON.parse(card.dataset.tags || "[]") as string[];
|
|
427
|
+
} catch {
|
|
428
|
+
/* data-tags 解析失败时按无分组处理 */
|
|
429
|
+
}
|
|
430
|
+
const okGroup = !group || tags.includes(group);
|
|
431
|
+
const show = okKeyword && okGroup;
|
|
432
|
+
card.hidden = !show;
|
|
433
|
+
if (show) visible++;
|
|
434
|
+
}
|
|
435
|
+
if (empty) empty.hidden = visible > 0;
|
|
436
|
+
};
|
|
437
|
+
search?.addEventListener("input", () => {
|
|
438
|
+
keyword = (search.value || "").trim().toLowerCase();
|
|
439
|
+
applyFilter();
|
|
440
|
+
});
|
|
441
|
+
for (const pill of pills) {
|
|
442
|
+
pill.addEventListener("click", () => {
|
|
443
|
+
group = pill.dataset.friendPill || "";
|
|
444
|
+
for (const p of pills) p.classList.toggle("is-on", p === pill);
|
|
445
|
+
applyFilter();
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// 复制按钮:点击复制 data-copy 内容,短暂切换成功态
|
|
451
|
+
for (const btn of document.querySelectorAll<HTMLButtonElement>("[data-copy]")) {
|
|
452
|
+
btn.addEventListener("click", async () => {
|
|
453
|
+
const value = btn.dataset.copy || "";
|
|
454
|
+
try {
|
|
455
|
+
await navigator.clipboard.writeText(value);
|
|
456
|
+
} catch {
|
|
457
|
+
/* 剪贴板不可用时静默降级(按钮仍给出成功反馈) */
|
|
458
|
+
}
|
|
459
|
+
btn.classList.add("is-copied");
|
|
460
|
+
setTimeout(() => btn.classList.remove("is-copied"), 1500);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// 本站头像加载失败时回退字头像(外链头像 404 / 防盗链兜底)
|
|
465
|
+
const avatarBox = document.querySelector<HTMLElement>("[data-siteinfo-avatar]");
|
|
466
|
+
const avatarImg = avatarBox?.querySelector("img");
|
|
467
|
+
if (avatarBox && avatarImg) {
|
|
468
|
+
avatarImg.addEventListener("error", () => {
|
|
469
|
+
const fb = document.createElement("span");
|
|
470
|
+
fb.className = "avatar-fallback";
|
|
471
|
+
fb.textContent = (avatarBox.dataset.avatarName || "?").slice(0, 1);
|
|
472
|
+
avatarImg.replaceWith(fb);
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
</script>
|
package/src/schema.ts
CHANGED
|
@@ -706,6 +706,29 @@ export const themeConfigSchema = z.object({
|
|
|
706
706
|
description: z.string().default(""),
|
|
707
707
|
/** 页面级排序:weight 权重降序 / random 随机(构建期) */
|
|
708
708
|
sort: z.enum(["weight", "random"]).default("weight"),
|
|
709
|
+
/** 友链区块卡工具条:搜索框与分组 pills 开关(分组由 list tags 聚合,无 tags 自动隐藏) */
|
|
710
|
+
filter: z
|
|
711
|
+
.object({
|
|
712
|
+
search: z.boolean().default(true),
|
|
713
|
+
groups: z.boolean().default(true),
|
|
714
|
+
})
|
|
715
|
+
.default({ search: true, groups: true }),
|
|
716
|
+
/** 本站信息卡(name/desc/site/avatar 任一非空才渲染整卡) */
|
|
717
|
+
siteInfo: z
|
|
718
|
+
.object({
|
|
719
|
+
title: z.string().default("本站信息"),
|
|
720
|
+
name: z.string().default(""),
|
|
721
|
+
desc: z.string().default(""),
|
|
722
|
+
site: z.string().default(""),
|
|
723
|
+
avatar: z.string().default(""),
|
|
724
|
+
})
|
|
725
|
+
.default({
|
|
726
|
+
title: "本站信息",
|
|
727
|
+
name: "",
|
|
728
|
+
desc: "",
|
|
729
|
+
site: "",
|
|
730
|
+
avatar: "",
|
|
731
|
+
}),
|
|
709
732
|
/** 申请友链卡片(title 留空则整卡不渲染) */
|
|
710
733
|
apply: z
|
|
711
734
|
.object({
|
|
@@ -714,8 +737,47 @@ export const themeConfigSchema = z.object({
|
|
|
714
737
|
/** 申请入口链接(mailto 或表单页) */
|
|
715
738
|
link: z.string().default(""),
|
|
716
739
|
label: z.string().default("申请友链"),
|
|
740
|
+
/** 申请步骤(空数组不渲染) */
|
|
741
|
+
steps: z
|
|
742
|
+
.array(
|
|
743
|
+
z.object({
|
|
744
|
+
title: z.string(),
|
|
745
|
+
description: z.string().default(""),
|
|
746
|
+
}),
|
|
747
|
+
)
|
|
748
|
+
.default([]),
|
|
749
|
+
/** 可复制申请资料模板行(空数组不渲染) */
|
|
750
|
+
template: z
|
|
751
|
+
.array(
|
|
752
|
+
z.object({
|
|
753
|
+
label: z.string(),
|
|
754
|
+
value: z.string(),
|
|
755
|
+
}),
|
|
756
|
+
)
|
|
757
|
+
.default([]),
|
|
717
758
|
})
|
|
718
|
-
.default({
|
|
759
|
+
.default({
|
|
760
|
+
title: "",
|
|
761
|
+
description: "",
|
|
762
|
+
link: "",
|
|
763
|
+
label: "申请友链",
|
|
764
|
+
steps: [],
|
|
765
|
+
template: [],
|
|
766
|
+
}),
|
|
767
|
+
/** 注意事项卡(items 为空不渲染) */
|
|
768
|
+
notice: z
|
|
769
|
+
.object({
|
|
770
|
+
title: z.string().default("注意事项"),
|
|
771
|
+
items: z
|
|
772
|
+
.array(
|
|
773
|
+
z.object({
|
|
774
|
+
term: z.string(),
|
|
775
|
+
description: z.string().default(""),
|
|
776
|
+
}),
|
|
777
|
+
)
|
|
778
|
+
.default([]),
|
|
779
|
+
})
|
|
780
|
+
.default({ title: "注意事项", items: [] }),
|
|
719
781
|
list: z
|
|
720
782
|
.array(
|
|
721
783
|
z.object({
|
|
@@ -738,7 +800,17 @@ export const themeConfigSchema = z.object({
|
|
|
738
800
|
title: "友链",
|
|
739
801
|
description: "",
|
|
740
802
|
sort: "weight",
|
|
741
|
-
|
|
803
|
+
filter: { search: true, groups: true },
|
|
804
|
+
siteInfo: { title: "本站信息", name: "", desc: "", site: "", avatar: "" },
|
|
805
|
+
apply: {
|
|
806
|
+
title: "",
|
|
807
|
+
description: "",
|
|
808
|
+
link: "",
|
|
809
|
+
label: "申请友链",
|
|
810
|
+
steps: [],
|
|
811
|
+
template: [],
|
|
812
|
+
},
|
|
813
|
+
notice: { title: "注意事项", items: [] },
|
|
742
814
|
list: [],
|
|
743
815
|
}),
|
|
744
816
|
/**
|
package/src/styles/global.css
CHANGED
|
@@ -3373,7 +3373,9 @@ html.dark .outdated-warning {
|
|
|
3373
3373
|
border-radius: var(--radius-sm);
|
|
3374
3374
|
font-size: 14px;
|
|
3375
3375
|
color: var(--ink-2);
|
|
3376
|
-
transition:
|
|
3376
|
+
transition:
|
|
3377
|
+
background 0.15s ease,
|
|
3378
|
+
color 0.15s ease;
|
|
3377
3379
|
}
|
|
3378
3380
|
.post-resources-item a:hover {
|
|
3379
3381
|
background: var(--bg-soft);
|
|
@@ -4614,6 +4616,320 @@ html.dark .friend-card:hover .friend-name {
|
|
|
4614
4616
|
padding: 1px 9px;
|
|
4615
4617
|
}
|
|
4616
4618
|
|
|
4619
|
+
/* ---------- 10.3 友链区块卡(标题 + 搜索 + 分组 + 网格) ---------- */
|
|
4620
|
+
.friend-zone {
|
|
4621
|
+
margin-top: 26px;
|
|
4622
|
+
padding: 22px 24px;
|
|
4623
|
+
}
|
|
4624
|
+
.friend-toolbar {
|
|
4625
|
+
display: flex;
|
|
4626
|
+
align-items: center;
|
|
4627
|
+
gap: 12px;
|
|
4628
|
+
flex-wrap: wrap;
|
|
4629
|
+
}
|
|
4630
|
+
.friend-zone-title {
|
|
4631
|
+
display: flex;
|
|
4632
|
+
align-items: center;
|
|
4633
|
+
gap: 10px;
|
|
4634
|
+
font-family: var(--font-display);
|
|
4635
|
+
font-weight: 700;
|
|
4636
|
+
font-size: 17px;
|
|
4637
|
+
}
|
|
4638
|
+
.friend-zone-title svg {
|
|
4639
|
+
flex: none;
|
|
4640
|
+
width: 20px;
|
|
4641
|
+
height: 20px;
|
|
4642
|
+
color: var(--accent);
|
|
4643
|
+
}
|
|
4644
|
+
.friend-zone-desc {
|
|
4645
|
+
margin-top: 6px;
|
|
4646
|
+
font-size: 14px;
|
|
4647
|
+
color: var(--muted);
|
|
4648
|
+
line-height: 1.7;
|
|
4649
|
+
}
|
|
4650
|
+
.friend-search {
|
|
4651
|
+
margin-left: auto;
|
|
4652
|
+
display: flex;
|
|
4653
|
+
align-items: center;
|
|
4654
|
+
gap: 8px;
|
|
4655
|
+
width: min(230px, 100%);
|
|
4656
|
+
padding: 7px 12px;
|
|
4657
|
+
border: 1px solid var(--border);
|
|
4658
|
+
border-radius: 999px;
|
|
4659
|
+
background: var(--bg-soft);
|
|
4660
|
+
transition: border-color 0.15s;
|
|
4661
|
+
}
|
|
4662
|
+
.friend-search:focus-within {
|
|
4663
|
+
border-color: var(--accent);
|
|
4664
|
+
}
|
|
4665
|
+
.friend-search svg {
|
|
4666
|
+
flex: none;
|
|
4667
|
+
width: 15px;
|
|
4668
|
+
height: 15px;
|
|
4669
|
+
color: var(--muted);
|
|
4670
|
+
}
|
|
4671
|
+
.friend-search input {
|
|
4672
|
+
flex: 1;
|
|
4673
|
+
min-width: 0;
|
|
4674
|
+
border: none;
|
|
4675
|
+
background: transparent;
|
|
4676
|
+
outline: none;
|
|
4677
|
+
font-size: 13.5px;
|
|
4678
|
+
color: var(--ink);
|
|
4679
|
+
}
|
|
4680
|
+
.friend-search input::placeholder {
|
|
4681
|
+
color: var(--muted);
|
|
4682
|
+
}
|
|
4683
|
+
.friend-pills {
|
|
4684
|
+
margin-top: 14px;
|
|
4685
|
+
display: flex;
|
|
4686
|
+
flex-wrap: wrap;
|
|
4687
|
+
gap: 8px;
|
|
4688
|
+
}
|
|
4689
|
+
.friend-pills .chip {
|
|
4690
|
+
cursor: pointer;
|
|
4691
|
+
font-family: inherit;
|
|
4692
|
+
}
|
|
4693
|
+
.friend-zone .friend-grid {
|
|
4694
|
+
margin-top: 18px;
|
|
4695
|
+
}
|
|
4696
|
+
/* .friend-card 的 display:flex 会覆盖 UA 的 [hidden],需显式收回 */
|
|
4697
|
+
.friend-card[hidden],
|
|
4698
|
+
.tag-empty[hidden] {
|
|
4699
|
+
display: none;
|
|
4700
|
+
}
|
|
4701
|
+
.friend-zone .tag-empty {
|
|
4702
|
+
margin-top: 18px;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
/* ---------- 10.4 本站信息 / 申请友链 双卡与注意事项 ---------- */
|
|
4706
|
+
.friend-duo {
|
|
4707
|
+
margin-top: 20px;
|
|
4708
|
+
display: grid;
|
|
4709
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
4710
|
+
gap: 20px;
|
|
4711
|
+
}
|
|
4712
|
+
.friend-duo > .card:only-child {
|
|
4713
|
+
grid-column: 1 / -1;
|
|
4714
|
+
}
|
|
4715
|
+
@media (max-width: 767px) {
|
|
4716
|
+
.friend-duo {
|
|
4717
|
+
grid-template-columns: 1fr;
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
.friend-siteinfo,
|
|
4721
|
+
.friend-apply-card {
|
|
4722
|
+
display: flex;
|
|
4723
|
+
flex-direction: column;
|
|
4724
|
+
}
|
|
4725
|
+
.friend-siteinfo,
|
|
4726
|
+
.friend-apply-card,
|
|
4727
|
+
.friend-notice {
|
|
4728
|
+
padding: 22px 24px;
|
|
4729
|
+
}
|
|
4730
|
+
.friend-card-title {
|
|
4731
|
+
display: flex;
|
|
4732
|
+
align-items: center;
|
|
4733
|
+
gap: 10px;
|
|
4734
|
+
font-family: var(--font-display);
|
|
4735
|
+
font-weight: 700;
|
|
4736
|
+
font-size: 17px;
|
|
4737
|
+
}
|
|
4738
|
+
.friend-card-title svg {
|
|
4739
|
+
flex: none;
|
|
4740
|
+
width: 18px;
|
|
4741
|
+
height: 18px;
|
|
4742
|
+
color: var(--accent);
|
|
4743
|
+
}
|
|
4744
|
+
/* 本站信息卡头:头像 + 名称 + 描述(对齐参考布局) */
|
|
4745
|
+
.siteinfo-head {
|
|
4746
|
+
display: flex;
|
|
4747
|
+
align-items: center;
|
|
4748
|
+
gap: 12px;
|
|
4749
|
+
margin-top: 16px;
|
|
4750
|
+
}
|
|
4751
|
+
.siteinfo-avatar {
|
|
4752
|
+
flex: none;
|
|
4753
|
+
display: flex;
|
|
4754
|
+
align-items: center;
|
|
4755
|
+
justify-content: center;
|
|
4756
|
+
width: 48px;
|
|
4757
|
+
height: 48px;
|
|
4758
|
+
border-radius: 50%;
|
|
4759
|
+
overflow: hidden;
|
|
4760
|
+
border: 1px solid var(--border);
|
|
4761
|
+
background: var(--bg-soft);
|
|
4762
|
+
}
|
|
4763
|
+
.siteinfo-avatar img {
|
|
4764
|
+
width: 100%;
|
|
4765
|
+
height: 100%;
|
|
4766
|
+
object-fit: cover;
|
|
4767
|
+
}
|
|
4768
|
+
.siteinfo-meta {
|
|
4769
|
+
min-width: 0;
|
|
4770
|
+
}
|
|
4771
|
+
.siteinfo-name {
|
|
4772
|
+
font-family: var(--font-display);
|
|
4773
|
+
font-weight: 700;
|
|
4774
|
+
font-size: 15px;
|
|
4775
|
+
}
|
|
4776
|
+
.siteinfo-desc {
|
|
4777
|
+
margin-top: 2px;
|
|
4778
|
+
font-size: 13px;
|
|
4779
|
+
color: var(--muted);
|
|
4780
|
+
line-height: 1.5;
|
|
4781
|
+
}
|
|
4782
|
+
.kv-row {
|
|
4783
|
+
display: flex;
|
|
4784
|
+
align-items: center;
|
|
4785
|
+
gap: 10px;
|
|
4786
|
+
margin-top: 10px;
|
|
4787
|
+
padding: 10px 12px;
|
|
4788
|
+
background: var(--bg-soft);
|
|
4789
|
+
border: 1px solid var(--border);
|
|
4790
|
+
border-radius: 8px;
|
|
4791
|
+
}
|
|
4792
|
+
.kv-main {
|
|
4793
|
+
flex: 1;
|
|
4794
|
+
min-width: 0;
|
|
4795
|
+
display: flex;
|
|
4796
|
+
flex-direction: column;
|
|
4797
|
+
gap: 2px;
|
|
4798
|
+
}
|
|
4799
|
+
.kv-label {
|
|
4800
|
+
font-size: 12px;
|
|
4801
|
+
color: var(--muted);
|
|
4802
|
+
}
|
|
4803
|
+
.kv-value {
|
|
4804
|
+
font-size: 13.5px;
|
|
4805
|
+
color: var(--ink);
|
|
4806
|
+
line-height: 1.5;
|
|
4807
|
+
word-break: break-all;
|
|
4808
|
+
}
|
|
4809
|
+
.copy-btn {
|
|
4810
|
+
flex: none;
|
|
4811
|
+
display: inline-flex;
|
|
4812
|
+
align-items: center;
|
|
4813
|
+
justify-content: center;
|
|
4814
|
+
width: 26px;
|
|
4815
|
+
height: 26px;
|
|
4816
|
+
border: 1px solid var(--border);
|
|
4817
|
+
border-radius: 6px;
|
|
4818
|
+
background: transparent;
|
|
4819
|
+
color: var(--muted);
|
|
4820
|
+
cursor: pointer;
|
|
4821
|
+
transition:
|
|
4822
|
+
color 0.15s,
|
|
4823
|
+
border-color 0.15s;
|
|
4824
|
+
}
|
|
4825
|
+
.copy-btn:hover {
|
|
4826
|
+
color: var(--accent-ink);
|
|
4827
|
+
border-color: var(--accent);
|
|
4828
|
+
}
|
|
4829
|
+
.copy-btn svg {
|
|
4830
|
+
width: 14px;
|
|
4831
|
+
height: 14px;
|
|
4832
|
+
}
|
|
4833
|
+
.copy-btn .icon-check {
|
|
4834
|
+
display: none;
|
|
4835
|
+
}
|
|
4836
|
+
.copy-btn.is-copied {
|
|
4837
|
+
color: var(--accent-ink);
|
|
4838
|
+
border-color: var(--accent);
|
|
4839
|
+
}
|
|
4840
|
+
.copy-btn.is-copied .icon-copy {
|
|
4841
|
+
display: none;
|
|
4842
|
+
}
|
|
4843
|
+
.copy-btn.is-copied .icon-check {
|
|
4844
|
+
display: block;
|
|
4845
|
+
}
|
|
4846
|
+
.friend-apply-card .fa-desc {
|
|
4847
|
+
margin-top: 6px;
|
|
4848
|
+
font-size: 14px;
|
|
4849
|
+
color: var(--muted);
|
|
4850
|
+
line-height: 1.7;
|
|
4851
|
+
}
|
|
4852
|
+
.apply-steps {
|
|
4853
|
+
list-style: none;
|
|
4854
|
+
margin: 16px 0 0;
|
|
4855
|
+
padding: 0;
|
|
4856
|
+
display: grid;
|
|
4857
|
+
gap: 12px;
|
|
4858
|
+
}
|
|
4859
|
+
.apply-step {
|
|
4860
|
+
display: flex;
|
|
4861
|
+
align-items: flex-start;
|
|
4862
|
+
gap: 12px;
|
|
4863
|
+
}
|
|
4864
|
+
.apply-step-num {
|
|
4865
|
+
flex: none;
|
|
4866
|
+
display: inline-flex;
|
|
4867
|
+
align-items: center;
|
|
4868
|
+
justify-content: center;
|
|
4869
|
+
width: 22px;
|
|
4870
|
+
height: 22px;
|
|
4871
|
+
border-radius: 50%;
|
|
4872
|
+
background: var(--accent-soft);
|
|
4873
|
+
color: var(--accent-ink);
|
|
4874
|
+
font-size: 12px;
|
|
4875
|
+
font-weight: 700;
|
|
4876
|
+
margin-top: 1px;
|
|
4877
|
+
}
|
|
4878
|
+
.apply-step-title {
|
|
4879
|
+
font-weight: 600;
|
|
4880
|
+
font-size: 14.5px;
|
|
4881
|
+
}
|
|
4882
|
+
.apply-step-desc {
|
|
4883
|
+
margin-top: 2px;
|
|
4884
|
+
font-size: 13px;
|
|
4885
|
+
color: var(--muted);
|
|
4886
|
+
line-height: 1.6;
|
|
4887
|
+
}
|
|
4888
|
+
/* 申请资料模板:整块展示 + 右上角一键复制(对齐参考布局) */
|
|
4889
|
+
.apply-template {
|
|
4890
|
+
position: relative;
|
|
4891
|
+
margin-top: 14px;
|
|
4892
|
+
padding: 12px 46px 12px 16px;
|
|
4893
|
+
background: var(--bg-soft);
|
|
4894
|
+
border: 1px solid var(--border);
|
|
4895
|
+
border-radius: 8px;
|
|
4896
|
+
}
|
|
4897
|
+
.apply-template .copy-btn {
|
|
4898
|
+
position: absolute;
|
|
4899
|
+
top: 8px;
|
|
4900
|
+
right: 8px;
|
|
4901
|
+
}
|
|
4902
|
+
.apply-template-line {
|
|
4903
|
+
font-size: 13px;
|
|
4904
|
+
color: var(--ink);
|
|
4905
|
+
line-height: 1.9;
|
|
4906
|
+
word-break: break-all;
|
|
4907
|
+
}
|
|
4908
|
+
.friend-apply-card .btn {
|
|
4909
|
+
margin-top: 16px;
|
|
4910
|
+
width: 100%;
|
|
4911
|
+
justify-content: center;
|
|
4912
|
+
}
|
|
4913
|
+
.friend-notice {
|
|
4914
|
+
margin-top: 20px;
|
|
4915
|
+
}
|
|
4916
|
+
.notice-list {
|
|
4917
|
+
margin: 14px 0 0;
|
|
4918
|
+
padding: 0;
|
|
4919
|
+
display: grid;
|
|
4920
|
+
gap: 12px;
|
|
4921
|
+
}
|
|
4922
|
+
.notice-item dt {
|
|
4923
|
+
font-weight: 700;
|
|
4924
|
+
font-size: 14px;
|
|
4925
|
+
}
|
|
4926
|
+
.notice-item dd {
|
|
4927
|
+
margin: 2px 0 0;
|
|
4928
|
+
font-size: 13.5px;
|
|
4929
|
+
color: var(--muted);
|
|
4930
|
+
line-height: 1.7;
|
|
4931
|
+
}
|
|
4932
|
+
|
|
4617
4933
|
/* ---------- 10.1 字头像兜底(友链/打赏名单无图时) ---------- */
|
|
4618
4934
|
.avatar-fallback {
|
|
4619
4935
|
display: inline-flex;
|