feat: 首页门面 Feed 密度与侧栏分组
对齐 SPA 信息密度:头像/摘要/互动、高级搜索收起、浏览/板块分区。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,15 +10,15 @@
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| **上一刀** | 青主题产品化重绘 + 静态资源 `?v=` 版本号 |
|
||||
| **下一刀** | 需点名(移动侧栏抽屉 / OIDC Admin / S3 / Gitea / 表格表情…) |
|
||||
| **上一刀** | 首页门面精修(Feed 头像/摘要/互动 + 高级搜索收起 + 侧栏分组) |
|
||||
| **下一刀** | 需点名(移动侧栏抽屉 / 帖详情抛光 / OIDC Admin / S3…) |
|
||||
| **工作区** | 应干净 |
|
||||
|
||||
---
|
||||
|
||||
## 一句话状态
|
||||
|
||||
核心论坛、Admin、Limits/伪静态、嵌套评论、Markdown 编辑器、主题、公开页青主题产品壳与资源版本号已齐;本分支 `routers/api` 仅保留机器入口。余量多为后置与体验打磨。
|
||||
核心论坛、Admin、Limits/伪静态、嵌套评论、Markdown 编辑器、主题、清青产品壳与资源版本号、首页门面密度已齐;本分支 `routers/api` 仅保留机器入口。余量多为后置与体验打磨。
|
||||
|
||||
---
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
| Markdown 工具栏 + preview | 已迁 |
|
||||
| 浅色 / 暗色 / 跟随系统 | 已迁(CSS 媒体查询,无 head 防闪脚本) |
|
||||
| 未挂载论坛 JSON API | 已删(对照 `main`) |
|
||||
| 公开页设计系统 | 已迁(清青产品 chrome + `?v=`;[10-design-system.md](10-design-system.md)) |
|
||||
| 公开页设计系统 | 已迁(清青 chrome + `?v=` + 首页 Feed 门面密度) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -82,16 +82,18 @@
|
||||
|
||||
| 组件 | 规则 |
|
||||
|------|------|
|
||||
| 顶栏 | 品牌 \| 搜索条 \| 发帖主按钮 + 主题 + 私信 + 用户 +「更多」菜单;告别链接墙 |
|
||||
| 侧栏链 | sm;active = soft 底 + 左边青条 |
|
||||
| Feed | 排序分段控件;搜索扁平工具条;细线列表;回复数右对齐强调 |
|
||||
| 标签 / 按钮 / 评论 / 门控 | 同青 token;列表仍非卡片墙 |
|
||||
| 顶栏 | 品牌 \| 搜索条 \|「+ 发帖」主按钮 + 主题 + 私信 + 用户 +「更多」;告别链接墙 |
|
||||
| 左栏 | 分区「浏览 / 板块」;active = soft 底 + 左边青条 |
|
||||
| Feed 行 | 头像 · 作者+相对时间 / 标题 / 摘要(最多 2 行)/ 标签 · 右栏回复/赞/阅读;细线分隔非卡片墙 |
|
||||
| 高级搜索 | `<details>` 默认收起;有筛选条件或错误时展开;顶栏搜索仍 `/?keyword=` |
|
||||
| 排序 | 分段控件 |
|
||||
| 标签 / 按钮 / 评论 / 门控 | 同青 token |
|
||||
|
||||
---
|
||||
|
||||
## 5. 范围边界
|
||||
|
||||
- **覆盖**:公开页壳层、资源 `?v=`、浅/暗色
|
||||
- **覆盖**:公开页壳层(含首页门面密度)、资源 `?v=`、浅/暗色
|
||||
- **不覆盖**:Admin 深重绘、移动抽屉、虚拟滚动、TipTap、改站名
|
||||
|
||||
交叉:[06-pages-ux.md](06-pages-ux.md) · [09-ssr-progress.md](09-ssr-progress.md)
|
||||
|
||||
@@ -303,14 +303,21 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
background: transparent;
|
||||
color: var(--j13-muted);
|
||||
border-radius: var(--j13-radius);
|
||||
padding: 0.3rem 0.55rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
font: inherit;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
line-height: 1.3;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
transition: color var(--j13-ease), border-color var(--j13-ease), background-color var(--j13-ease);
|
||||
}
|
||||
.j13-theme-toggle__icon {
|
||||
flex-shrink: 0;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.j13-theme-toggle:hover {
|
||||
color: var(--j13-accent-ink);
|
||||
border-color: var(--j13-accent);
|
||||
@@ -415,6 +422,16 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
position: sticky;
|
||||
top: calc(var(--j13-header-h) + 0.75rem);
|
||||
}
|
||||
.j13-aside__section {
|
||||
margin: 0.85rem 0 0.35rem;
|
||||
padding: 0 0.55rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--j13-muted);
|
||||
}
|
||||
.j13-aside__section:first-child { margin-top: 0.15rem; }
|
||||
.j13-aside__link {
|
||||
padding: 0.45rem 0.6rem;
|
||||
border-radius: var(--j13-radius);
|
||||
@@ -450,7 +467,7 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
margin-bottom: 0.65rem;
|
||||
}
|
||||
.j13-feed__title {
|
||||
margin: 0;
|
||||
@@ -485,13 +502,44 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
background: var(--j13-hover);
|
||||
}
|
||||
|
||||
.j13-search-advanced {
|
||||
margin: 0 0 0.75rem;
|
||||
scroll-margin-top: 4.5rem;
|
||||
}
|
||||
.j13-search-advanced__summary {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
color: var(--j13-muted);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
padding: 0.25rem 0;
|
||||
user-select: none;
|
||||
}
|
||||
.j13-search-advanced__summary::-webkit-details-marker { display: none; }
|
||||
.j13-search-advanced__summary::before {
|
||||
content: "";
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
border-right: 1.5px solid currentColor;
|
||||
border-bottom: 1.5px solid currentColor;
|
||||
transform: rotate(-45deg);
|
||||
transition: transform var(--j13-ease);
|
||||
}
|
||||
.j13-search-advanced[open] > .j13-search-advanced__summary::before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.j13-search-advanced__summary:hover { color: var(--j13-accent); }
|
||||
.j13-search-advanced .j13-search { margin-top: 0.45rem; }
|
||||
|
||||
.j13-search {
|
||||
margin: 0 0 0.85rem;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
scroll-margin-top: 4.5rem;
|
||||
}
|
||||
.j13-search--toolbar .j13-search__row {
|
||||
display: flex;
|
||||
@@ -541,38 +589,114 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
|
||||
.j13-post-list { list-style: none; margin: 0; padding: 0; }
|
||||
.j13-post-item {
|
||||
padding: 0.85rem 0.4rem;
|
||||
margin: 0 -0.4rem;
|
||||
display: grid;
|
||||
grid-template-columns: 2.5rem minmax(0, 1fr) auto;
|
||||
gap: 0.75rem 0.85rem;
|
||||
padding: 1rem 0.45rem;
|
||||
margin: 0 -0.45rem;
|
||||
border-top: 1px solid var(--j13-border);
|
||||
border-radius: var(--j13-radius);
|
||||
transition: background-color var(--j13-ease);
|
||||
align-items: start;
|
||||
}
|
||||
.j13-post-item:first-child { border-top: 0; }
|
||||
.j13-post-item:hover { background: var(--j13-hover); }
|
||||
.j13-post-item__avatar {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
background: var(--j13-soft);
|
||||
}
|
||||
.j13-post-item__avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.j13-post-item__mark {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
color: var(--j13-accent-ink);
|
||||
background: var(--j13-soft);
|
||||
}
|
||||
.j13-post-item__body { min-width: 0; }
|
||||
.j13-post-item__byline {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem 0.65rem;
|
||||
align-items: baseline;
|
||||
font-size: 0.75rem;
|
||||
color: var(--j13-muted);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.j13-post-item__byline a {
|
||||
color: var(--j13-accent-ink);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.j13-post-item__byline a:hover { color: var(--j13-accent); }
|
||||
.j13-post-item__title {
|
||||
display: inline-block;
|
||||
color: var(--j13-text);
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
font-size: 1.15rem;
|
||||
font-size: 1.1rem;
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.35;
|
||||
transition: color var(--j13-ease);
|
||||
}
|
||||
.j13-post-item__title:hover { color: var(--j13-accent); }
|
||||
.j13-post-item__excerpt {
|
||||
margin: 0.3rem 0 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
color: var(--j13-muted);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.j13-post-item__meta {
|
||||
margin-top: 0.35rem;
|
||||
margin-top: 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--j13-muted);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.45rem;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
.j13-post-item__replies {
|
||||
margin-left: auto;
|
||||
.j13-post-item__stats {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
align-items: flex-end;
|
||||
font-size: 0.72rem;
|
||||
color: var(--j13-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
padding-top: 0.15rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.j13-post-item__stats strong {
|
||||
font-weight: 650;
|
||||
color: var(--j13-accent-ink);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.j13-post-item {
|
||||
grid-template-columns: 2.25rem minmax(0, 1fr);
|
||||
}
|
||||
.j13-post-item__stats {
|
||||
grid-column: 2;
|
||||
flex-direction: row;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.j13-widget__title {
|
||||
|
||||
@@ -27,9 +27,15 @@ document.documentElement.dataset.j13Ssr = "1";
|
||||
} catch (e) {}
|
||||
var btn = document.getElementById("j13-theme-toggle");
|
||||
if (btn) {
|
||||
btn.textContent = LABELS[pref] || LABELS.system;
|
||||
btn.setAttribute("aria-label", "主题:" + (LABELS[pref] || ""));
|
||||
btn.title = "当前:" + (LABELS[pref] || "") + "(点击切换)";
|
||||
var label = btn.querySelector(".j13-theme-toggle__label");
|
||||
var text = LABELS[pref] || LABELS.system;
|
||||
if (label) {
|
||||
label.textContent = text;
|
||||
} else {
|
||||
btn.textContent = text;
|
||||
}
|
||||
btn.setAttribute("aria-label", "主题:" + text);
|
||||
btn.title = "当前:" + text + "(点击切换)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,11 +169,18 @@ type PostListItem struct {
|
||||
ID uint
|
||||
Title string
|
||||
Href string
|
||||
AuthorID uint
|
||||
AuthorName string
|
||||
AuthorHref string
|
||||
AvatarURL string
|
||||
AuthorMark string // 无头像时的单字占位
|
||||
BoardName string
|
||||
Excerpt string
|
||||
Pinned bool
|
||||
Featured bool
|
||||
CommentCount int
|
||||
LikeCount int
|
||||
ViewCount int
|
||||
CreatedLabel string
|
||||
}
|
||||
|
||||
@@ -329,10 +336,26 @@ func (d Deps) Home(c *gin.Context) {
|
||||
if it.Board.ID > 0 {
|
||||
bname = it.Board.Name
|
||||
}
|
||||
excerptSrc := strings.TrimSpace(it.ContentPlain)
|
||||
if excerptSrc == "" {
|
||||
excerptSrc = services.ExcerptFromHTML(it.Content, 100)
|
||||
} else {
|
||||
excerptSrc = services.TruncateRunes(excerptSrc, 100)
|
||||
}
|
||||
avatar := strings.TrimSpace(it.User.Avatar)
|
||||
authorID := it.UserID
|
||||
authorHref := ""
|
||||
if authorID > 0 {
|
||||
authorHref = pl.UserPath(authorID)
|
||||
}
|
||||
posts = append(posts, PostListItem{
|
||||
ID: it.ID, Title: it.Title, Href: pl.PostPath(it.ID), AuthorName: authorName, BoardName: bname,
|
||||
Pinned: it.Pinned, Featured: it.Featured, CommentCount: it.CommentCount,
|
||||
CreatedLabel: it.CreatedAt.Local().Format("2006-01-02 15:04"),
|
||||
ID: it.ID, Title: it.Title, Href: pl.PostPath(it.ID),
|
||||
AuthorID: authorID, AuthorName: authorName, AuthorHref: authorHref,
|
||||
AvatarURL: avatar, AuthorMark: firstRuneOr(authorName, "姜"),
|
||||
BoardName: bname, Excerpt: excerptSrc,
|
||||
Pinned: it.Pinned, Featured: it.Featured,
|
||||
CommentCount: it.CommentCount, LikeCount: it.LikeCount, ViewCount: it.ViewCount,
|
||||
CreatedLabel: formatRelativeTime(it.CreatedAt),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -353,3 +376,29 @@ func normalizeSort(s string) string {
|
||||
func formatTime(t time.Time) string {
|
||||
return t.Local().Format("2006-01-02 15:04")
|
||||
}
|
||||
|
||||
// formatRelativeTime 列表用相对时间
|
||||
func formatRelativeTime(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return ""
|
||||
}
|
||||
now := time.Now()
|
||||
d := now.Sub(t)
|
||||
if d < 0 {
|
||||
d = 0
|
||||
}
|
||||
switch {
|
||||
case d < time.Minute:
|
||||
return "刚刚"
|
||||
case d < time.Hour:
|
||||
return fmt.Sprintf("%d 分钟前", int(d.Minutes()))
|
||||
case d < 24*time.Hour:
|
||||
return fmt.Sprintf("%d 小时前", int(d.Hours()))
|
||||
case d < 48*time.Hour:
|
||||
return "昨天"
|
||||
case d < 30*24*time.Hour:
|
||||
return fmt.Sprintf("%d 天前", int(d.Hours()/24))
|
||||
default:
|
||||
return t.Local().Format("2006-01-02")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,20 @@
|
||||
</form>
|
||||
<div class="j13-header__actions">
|
||||
{{if .LoggedIn}}
|
||||
<a class="j13-btn j13-btn--compose" href="/compose">发帖</a>
|
||||
<a class="j13-btn j13-btn--compose" href="/compose">+ 发帖</a>
|
||||
{{else}}
|
||||
<a class="j13-btn j13-btn--compose" href="/login">登录</a>
|
||||
<a class="j13-header__textlink" href="/register">注册</a>
|
||||
{{end}}
|
||||
<button type="button" class="j13-theme-toggle" id="j13-theme-toggle" aria-label="切换主题" title="切换主题">主题</button>
|
||||
<button type="button" class="j13-theme-toggle" id="j13-theme-toggle" aria-label="切换主题" title="切换主题">
|
||||
<svg class="j13-theme-toggle__icon" width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M12 3a1 1 0 0 1 1 1v1.06a7.5 7.5 0 1 1-2 0V4a1 1 0 0 1 1-1Zm0 4.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z"/>
|
||||
</svg>
|
||||
<span class="j13-theme-toggle__label">主题</span>
|
||||
</button>
|
||||
{{if .LoggedIn}}
|
||||
<a class="j13-header__iconlink" href="/messages" title="私信">私信{{if gt .UnreadCount 0}} <span class="j13-badge">{{.UnreadCount}}</span>{{end}}</a>
|
||||
<a class="j13-header__user" href="/profile" title="个人中心">{{.ViewerName}} · {{.ViewerPoints}}</a>
|
||||
<a class="j13-header__user" href="/profile" title="个人中心">{{.ViewerName}}</a>
|
||||
{{end}}
|
||||
<details class="j13-more">
|
||||
<summary>更多</summary>
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
<a class="{{if eq .Sort "hot"}}is-active{{end}}" href="{{.SortHref "hot"}}">热门讨论</a>
|
||||
</div>
|
||||
</header>
|
||||
<form id="search" class="j13-search j13-search--toolbar" method="get" action="{{.FormAction}}" role="search">
|
||||
<details class="j13-search-advanced" id="search"{{if or .HasSearch .TitleOnly .SearchError}} open{{end}}>
|
||||
<summary class="j13-search-advanced__summary">高级搜索</summary>
|
||||
<form class="j13-search j13-search--toolbar" method="get" action="{{.FormAction}}" role="search">
|
||||
{{if and .Sort (ne .Sort "latest")}}<input type="hidden" name="sort" value="{{.Sort}}"/>{{end}}
|
||||
<div class="j13-search__row">
|
||||
<label class="j13-search__field">
|
||||
@@ -31,20 +33,37 @@
|
||||
</div>
|
||||
{{if .SearchError}}<p class="j13-search__err" role="alert">{{.SearchError}}</p>{{end}}
|
||||
</form>
|
||||
</details>
|
||||
{{if not .Posts}}
|
||||
<p class="j13-empty">{{if .SearchError}}请调整搜索条件后重试。{{else if .HasSearch}}未找到匹配帖子。{{else}}暂无帖子。{{end}}</p>
|
||||
{{else}}
|
||||
<ul class="j13-post-list">
|
||||
{{range .Posts}}
|
||||
<li class="j13-post-item">
|
||||
<div class="j13-post-item__avatar">
|
||||
{{if .AvatarURL}}
|
||||
<img src="{{.AvatarURL}}" alt="" width="40" height="40"/>
|
||||
{{else}}
|
||||
<span class="j13-post-item__mark" aria-hidden="true">{{.AuthorMark}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="j13-post-item__body">
|
||||
<div class="j13-post-item__byline">
|
||||
{{if .AuthorHref}}<a href="{{.AuthorHref}}">{{.AuthorName}}</a>{{else}}<span>{{.AuthorName}}</span>{{end}}
|
||||
<span class="j13-post-item__time">{{.CreatedLabel}}</span>
|
||||
</div>
|
||||
<a class="j13-post-item__title" href="{{.Href}}"{{if $.OpenPostsInNewTab}} target="_blank" rel="noopener"{{end}}>{{.Title}}</a>
|
||||
{{if .Excerpt}}<p class="j13-post-item__excerpt">{{.Excerpt}}</p>{{end}}
|
||||
<div class="j13-post-item__meta">
|
||||
{{if .Pinned}}<span class="j13-tag j13-tag--pin">置顶</span>{{end}}
|
||||
{{if .Featured}}<span class="j13-tag j13-tag--feat">精华</span>{{end}}
|
||||
{{if .BoardName}}<span class="j13-tag">{{.BoardName}}</span>{{end}}
|
||||
<span>{{.AuthorName}}</span>
|
||||
<span>{{.CreatedLabel}}</span>
|
||||
<span class="j13-post-item__replies">{{.CommentCount}} 回复</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="j13-post-item__stats" aria-label="互动">
|
||||
<span title="回复"><strong>{{.CommentCount}}</strong> 回复</span>
|
||||
<span title="赞"><strong>{{.LikeCount}}</strong> 赞</span>
|
||||
<span title="阅读"><strong>{{.ViewCount}}</strong> 阅读</span>
|
||||
</div>
|
||||
</li>
|
||||
{{end}}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{{define "shared/board_aside"}}
|
||||
<aside class="j13-aside j13-aside--left">
|
||||
<p class="j13-aside__section">浏览</p>
|
||||
<a class="j13-aside__link{{if and (eq .ActiveBoard 0) (ne .Path "/boards") (ne .Path "/favorites")}} is-active{{end}}" href="/">全部帖子</a>
|
||||
{{if .LoggedIn}}
|
||||
<a class="j13-aside__link{{if eq .Path "/favorites"}} is-active{{end}}" href="/favorites">我的收藏</a>
|
||||
{{end}}
|
||||
<a class="j13-aside__link{{if eq .Path "/boards"}} is-active{{end}}" href="/boards">全部板块</a>
|
||||
<a class="j13-aside__link{{if and (eq .ActiveBoard 0) (ne .Path "/boards")}} is-active{{end}}" href="/">全部帖子</a>
|
||||
<p class="j13-aside__section">板块</p>
|
||||
{{range .Boards}}
|
||||
<a class="j13-aside__link{{if eq $.ActiveBoard .ID}} is-active{{end}}" href="{{.Href}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
|
||||
@@ -303,14 +303,21 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
background: transparent;
|
||||
color: var(--j13-muted);
|
||||
border-radius: var(--j13-radius);
|
||||
padding: 0.3rem 0.55rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
font: inherit;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
line-height: 1.3;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
transition: color var(--j13-ease), border-color var(--j13-ease), background-color var(--j13-ease);
|
||||
}
|
||||
.j13-theme-toggle__icon {
|
||||
flex-shrink: 0;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.j13-theme-toggle:hover {
|
||||
color: var(--j13-accent-ink);
|
||||
border-color: var(--j13-accent);
|
||||
@@ -415,6 +422,16 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
position: sticky;
|
||||
top: calc(var(--j13-header-h) + 0.75rem);
|
||||
}
|
||||
.j13-aside__section {
|
||||
margin: 0.85rem 0 0.35rem;
|
||||
padding: 0 0.55rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--j13-muted);
|
||||
}
|
||||
.j13-aside__section:first-child { margin-top: 0.15rem; }
|
||||
.j13-aside__link {
|
||||
padding: 0.45rem 0.6rem;
|
||||
border-radius: var(--j13-radius);
|
||||
@@ -450,7 +467,7 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
margin-bottom: 0.65rem;
|
||||
}
|
||||
.j13-feed__title {
|
||||
margin: 0;
|
||||
@@ -485,13 +502,44 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
background: var(--j13-hover);
|
||||
}
|
||||
|
||||
.j13-search-advanced {
|
||||
margin: 0 0 0.75rem;
|
||||
scroll-margin-top: 4.5rem;
|
||||
}
|
||||
.j13-search-advanced__summary {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
color: var(--j13-muted);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
padding: 0.25rem 0;
|
||||
user-select: none;
|
||||
}
|
||||
.j13-search-advanced__summary::-webkit-details-marker { display: none; }
|
||||
.j13-search-advanced__summary::before {
|
||||
content: "";
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
border-right: 1.5px solid currentColor;
|
||||
border-bottom: 1.5px solid currentColor;
|
||||
transform: rotate(-45deg);
|
||||
transition: transform var(--j13-ease);
|
||||
}
|
||||
.j13-search-advanced[open] > .j13-search-advanced__summary::before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.j13-search-advanced__summary:hover { color: var(--j13-accent); }
|
||||
.j13-search-advanced .j13-search { margin-top: 0.45rem; }
|
||||
|
||||
.j13-search {
|
||||
margin: 0 0 0.85rem;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
scroll-margin-top: 4.5rem;
|
||||
}
|
||||
.j13-search--toolbar .j13-search__row {
|
||||
display: flex;
|
||||
@@ -541,38 +589,114 @@ html[data-theme="dark"] .j13-brand__mark {
|
||||
|
||||
.j13-post-list { list-style: none; margin: 0; padding: 0; }
|
||||
.j13-post-item {
|
||||
padding: 0.85rem 0.4rem;
|
||||
margin: 0 -0.4rem;
|
||||
display: grid;
|
||||
grid-template-columns: 2.5rem minmax(0, 1fr) auto;
|
||||
gap: 0.75rem 0.85rem;
|
||||
padding: 1rem 0.45rem;
|
||||
margin: 0 -0.45rem;
|
||||
border-top: 1px solid var(--j13-border);
|
||||
border-radius: var(--j13-radius);
|
||||
transition: background-color var(--j13-ease);
|
||||
align-items: start;
|
||||
}
|
||||
.j13-post-item:first-child { border-top: 0; }
|
||||
.j13-post-item:hover { background: var(--j13-hover); }
|
||||
.j13-post-item__avatar {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
background: var(--j13-soft);
|
||||
}
|
||||
.j13-post-item__avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.j13-post-item__mark {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
color: var(--j13-accent-ink);
|
||||
background: var(--j13-soft);
|
||||
}
|
||||
.j13-post-item__body { min-width: 0; }
|
||||
.j13-post-item__byline {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem 0.65rem;
|
||||
align-items: baseline;
|
||||
font-size: 0.75rem;
|
||||
color: var(--j13-muted);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.j13-post-item__byline a {
|
||||
color: var(--j13-accent-ink);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.j13-post-item__byline a:hover { color: var(--j13-accent); }
|
||||
.j13-post-item__title {
|
||||
display: inline-block;
|
||||
color: var(--j13-text);
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
font-size: 1.15rem;
|
||||
font-size: 1.1rem;
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.35;
|
||||
transition: color var(--j13-ease);
|
||||
}
|
||||
.j13-post-item__title:hover { color: var(--j13-accent); }
|
||||
.j13-post-item__excerpt {
|
||||
margin: 0.3rem 0 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
color: var(--j13-muted);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.j13-post-item__meta {
|
||||
margin-top: 0.35rem;
|
||||
margin-top: 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--j13-muted);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.45rem;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
.j13-post-item__replies {
|
||||
margin-left: auto;
|
||||
.j13-post-item__stats {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
align-items: flex-end;
|
||||
font-size: 0.72rem;
|
||||
color: var(--j13-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
padding-top: 0.15rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.j13-post-item__stats strong {
|
||||
font-weight: 650;
|
||||
color: var(--j13-accent-ink);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.j13-post-item {
|
||||
grid-template-columns: 2.25rem minmax(0, 1fr);
|
||||
}
|
||||
.j13-post-item__stats {
|
||||
grid-column: 2;
|
||||
flex-direction: row;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.j13-widget__title {
|
||||
|
||||
@@ -27,9 +27,15 @@ document.documentElement.dataset.j13Ssr = "1";
|
||||
} catch (e) {}
|
||||
var btn = document.getElementById("j13-theme-toggle");
|
||||
if (btn) {
|
||||
btn.textContent = LABELS[pref] || LABELS.system;
|
||||
btn.setAttribute("aria-label", "主题:" + (LABELS[pref] || ""));
|
||||
btn.title = "当前:" + (LABELS[pref] || "") + "(点击切换)";
|
||||
var label = btn.querySelector(".j13-theme-toggle__label");
|
||||
var text = LABELS[pref] || LABELS.system;
|
||||
if (label) {
|
||||
label.textContent = text;
|
||||
} else {
|
||||
btn.textContent = text;
|
||||
}
|
||||
btn.setAttribute("aria-label", "主题:" + text);
|
||||
btn.title = "当前:" + text + "(点击切换)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user