feat: 首页对齐 main SPA 草绿壳与 Feed v2

顶栏搜索胶囊/发帖绿钮/Ctrl+K,侧栏板块色槽,列表 post-row--v2 与 SPA 同密度。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 06:06:04 +08:00
parent 6e7b46a2e9
commit 2ba010f3ea
11 changed files with 1549 additions and 258 deletions

View File

@@ -1,56 +1,66 @@
{{define "base/navbar"}}
<header class="j13-header">
<div class="j13-header__inner">
<a class="j13-brand" href="/">
<header class="j13-header app-header">
<div class="j13-header__inner header-inner">
<a class="j13-brand header-brand" href="/">
{{if .LogoURL}}
<img class="j13-brand__logo" src="{{.LogoURL}}" alt="{{.SiteName}}"/>
<img class="j13-brand__logo header-logo-mark" src="{{.LogoURL}}" alt="{{.SiteName}}"/>
{{else}}
<span class="j13-brand__mark">{{.LogoMark}}</span>
<span class="j13-brand__mark header-logo-mark">{{.LogoMark}}</span>
{{end}}
<span class="j13-brand__text">
<strong>{{.SiteName}}</strong>
{{if .Slogan}}<span class="j13-brand__slogan">{{.Slogan}}</span>{{end}}
</span>
<span class="header-logo-text">{{.SiteName}}</span>
</a>
<form class="j13-header-search" method="get" action="/" role="search">
<label class="j13-header-search__label">
<span class="j13-visually-hidden">搜索帖子</span>
<input type="search" name="keyword" placeholder="搜索帖子…" autocomplete="off"/>
</label>
<form class="header-search-wrap" method="get" action="/" role="search" id="j13-header-search">
<div class="header-search-row">
<svg class="header-search-icon" width="15" height="15" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M10.5 3a7.5 7.5 0 015.95 12.1l4.22 4.23a1 1 0 01-1.42 1.41l-4.22-4.22A7.5 7.5 0 1110.5 3zm0 2a5.5 5.5 0 100 11 5.5 5.5 0 000-11z"/></svg>
<input class="header-search-input" id="j13-header-search-input" type="search" name="keyword" value="" placeholder="搜索帖子…" autocomplete="off"/>
<button type="button" class="header-search-filter-btn" id="j13-search-filter-btn" aria-label="高级筛选" title="高级筛选">
<svg width="14" height="14" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M3 5h18v2.17L14 14v5l-4 2v-7L3 7.17V5z"/></svg>
</button>
<kbd class="header-search-kbd" aria-hidden="true">Ctrl K</kbd>
</div>
</form>
<div class="j13-header__actions">
<div class="header-actions">
{{if .LoggedIn}}
<a class="j13-btn j13-btn--compose" href="/compose">+ 发帖</a>
<a class="header-compose-btn" href="/compose"><span aria-hidden="true">+</span> 发帖</a>
{{else}}
<a class="j13-btn j13-btn--compose" href="/login">登录</a>
<a class="j13-header__textlink" href="/register">注册</a>
<a class="header-compose-btn" href="/login">登录</a>
{{end}}
<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}}</a>
{{end}}
<details class="j13-more">
<summary>更多</summary>
<div class="j13-more__menu" role="menu">
<a href="/boards" role="menuitem">板块</a>
{{if .ShowFriendLinksNav}}<a href="/links" role="menuitem">友链</a>{{end}}
{{range .NavPages}}<a href="/page/{{.Slug}}" role="menuitem">{{.Title}}</a>{{end}}
{{if .LoggedIn}}
<a href="/favorites" role="menuitem">收藏</a>
{{if .IsAdmin}}<a href="/admin/dashboard" role="menuitem">后台</a>{{end}}
<form method="post" action="/logout">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<button type="submit" role="menuitem">退出</button>
</form>
{{end}}
</div>
</details>
<div class="header-action-group">
<button type="button" class="header-icon-btn 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"><path fill="currentColor" d="M21 14.3A8.5 8.5 0 019.7 3 7 7 0 1019 16.5c.7-.6 1.3-1.4 2-2.2z"/></svg>
<span class="j13-visually-hidden j13-theme-toggle__label">主题</span>
</button>
{{if .LoggedIn}}
<a class="header-icon-btn" href="/messages" title="私信" aria-label="私信">
<svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M4 4h16a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2zm0 2v.51l8 5.33 8-5.33V6H4zm16 3.04l-7.45 4.97a1 1 0 01-1.1 0L4 9.04V18h16V9.04z"/></svg>
{{if gt .UnreadCount 0}}<span class="j13-badge">{{.UnreadCount}}</span>{{end}}
</a>
<details class="j13-more header-user-menu">
<summary class="header-user-btn" title="{{.ViewerName}}">
{{if .ViewerAvatar}}
<img class="header-user-avatar" src="{{.ViewerAvatar}}" alt=""/>
{{else}}
<span class="header-user-initial">{{.ViewerMark}}</span>
{{end}}
</summary>
<div class="j13-more__menu" role="menu">
<a href="/profile" role="menuitem">{{.ViewerName}} · {{.ViewerPoints}} 积分</a>
<a href="/favorites" role="menuitem">收藏</a>
<a href="/messages" role="menuitem">私信</a>
{{if .IsAdmin}}<a href="/admin/dashboard" role="menuitem">后台</a>{{end}}
{{if .ShowFriendLinksNav}}<a href="/links" role="menuitem">友链</a>{{end}}
{{range .NavPages}}<a href="/page/{{.Slug}}" role="menuitem">{{.Title}}</a>{{end}}
<a href="/boards" role="menuitem">板块</a>
<form method="post" action="/logout">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<button type="submit" role="menuitem">退出</button>
</form>
</div>
</details>
{{else}}
<a class="header-login-btn" href="/register">注册</a>
{{end}}
</div>
</div>
</div>
</header>

View File

@@ -1,14 +1,13 @@
{{define "home/feed"}}
<section class="j13-feed">
<header class="j13-feed__header">
<h1 class="j13-feed__title">{{if .BoardName}}{{.BoardName}}{{else}}全部帖子{{end}}</h1>
<div class="j13-sort" role="navigation" aria-label="排序">
<a class="{{if eq .Sort "latest"}}is-active{{end}}" href="{{.SortHref "latest"}}">最新发帖</a>
<a class="{{if eq .Sort "reply"}}is-active{{end}}" href="{{.SortHref "reply"}}">最新回复</a>
<a class="{{if eq .Sort "hot"}}is-active{{end}}" href="{{.SortHref "hot"}}">热门讨论</a>
<header class="feed-toolbar j13-feed__header">
<div class="feed-sort-bar j13-sort" role="tablist" aria-label="排序">
<a role="tab" class="feed-sort-tab{{if eq .Sort "latest"}} active is-active{{end}}" href="{{.SortHref "latest"}}">最新发帖</a>
<a role="tab" class="feed-sort-tab{{if eq .Sort "reply"}} active is-active{{end}}" href="{{.SortHref "reply"}}">最新回复</a>
<a role="tab" class="feed-sort-tab{{if eq .Sort "hot"}} active is-active{{end}}" href="{{.SortHref "hot"}}">热门讨论</a>
</div>
</header>
<details class="j13-search-advanced" id="search"{{if or .HasSearch .TitleOnly .SearchError}} open{{end}}>
<details class="j13-search-advanced post-search-panel" 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}}
@@ -37,34 +36,52 @@
{{if not .Posts}}
<p class="j13-empty">{{if .SearchError}}请调整搜索条件后重试。{{else if .HasSearch}}未找到匹配帖子。{{else}}暂无帖子。{{end}}</p>
{{else}}
<ul class="j13-post-list">
<ul class="j13-post-list post-list">
{{range .Posts}}
<li class="j13-post-item">
<div class="j13-post-item__avatar">
<li class="post-row post-row--v2{{if eq $.FeedListStyle "title"}} post-row--title-only{{end}}{{if .ThumbURL}} post-row--has-thumb{{end}}">
<div class="post-avatar">
{{if .AvatarURL}}
<img src="{{.AvatarURL}}" alt="" width="40" height="40"/>
<img src="{{.AvatarURL}}" alt=""/>
{{else}}
<span class="j13-post-item__mark" aria-hidden="true">{{.AuthorMark}}</span>
<span>{{.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 class="post-main{{if .ThumbURL}} post-main--with-thumb{{end}}">
<div class="post-content">
<div class="post-title-row">
{{if .Pinned}}<span class="post-pin-badge">全局置顶</span>{{end}}
{{if .BoardPinned}}<span class="post-pin-badge post-pin-badge--board">板块置顶</span>{{end}}
{{if .Featured}}<span class="post-feature-badge">精华</span>{{end}}
<a class="post-title" href="{{.Href}}"{{if $.OpenPostsInNewTab}} target="_blank" rel="noopener"{{end}}>{{.Title}}</a>
</div>
{{if and $.ShowExcerpt .Excerpt}}<p class="post-excerpt">{{.Excerpt}}</p>{{end}}
<div class="post-meta post-meta--inline">
<div class="post-meta-left">
{{if .ShowBoardBadge}}
<a class="post-list-board-badge board-badge--{{.BoardColorSlot}}" href="{{.BoardHref}}">{{.BoardName}}</a>
{{end}}
{{if .AuthorHref}}<a class="post-meta-author" href="{{.AuthorHref}}">{{.AuthorName}}</a>{{else}}<span class="post-meta-author">{{.AuthorName}}</span>{{end}}
<span class="post-meta-sep" aria-hidden>·</span>
<span class="post-meta-time">{{.CreatedLabel}}</span>
{{if .ShowLastReply}}
<span class="post-meta-last-reply">
<span aria-hidden>←</span>
{{if .LastReplyHref}}<a href="{{.LastReplyHref}}">{{.LastReplyName}}</a>{{else}}<span>{{.LastReplyName}}</span>{{end}}
<span>{{.LastReplyLabel}}</span>
</span>
{{end}}
</div>
</div>
</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}}
<div class="post-aside">
{{if .ThumbURL}}
<a class="post-thumb" href="{{.Href}}" tabindex="-1" aria-hidden="true"><img src="{{.ThumbURL}}" alt=""/></a>
{{end}}
<div class="post-stats">
<span class="post-stat" title="回复"><svg width="12" height="12" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M4 4h16a2 2 0 012 2v9a2 2 0 01-2 2H9l-5 4v-4H4a2 2 0 01-2-2V6a2 2 0 012-2z"/></svg> {{.CommentCount}}</span>
</div>
</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}}
</ul>

View File

@@ -1,14 +1,22 @@
{{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>
<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}}
<aside class="j13-aside j13-aside--left sidebar" aria-label="导航">
<p class="sidebar-section">浏览</p>
<nav class="sidebar-nav">
<a class="sidebar-nav-item{{if and (eq .ActiveBoard 0) (ne .Path "/boards") (ne .Path "/favorites")}} active{{end}}" href="/">全部帖子</a>
{{if .LoggedIn}}
<a class="sidebar-nav-item{{if eq .Path "/favorites"}} active{{end}}" href="/favorites">我的收藏</a>
{{end}}
<a class="sidebar-nav-item{{if eq .Path "/boards"}} active{{end}}" href="/boards">全部板块</a>
</nav>
<p class="sidebar-section sidebar-section--boards">板块</p>
<nav class="sidebar-nav">
{{range .Boards}}
<a class="sidebar-nav-item sidebar-nav-item--board sidebar-nav-item--board-{{.ColorSlot}}{{if eq $.ActiveBoard .ID}} active{{end}}" href="{{.Href}}">
<span class="sidebar-board-icon sidebar-board-icon--{{.ColorSlot}}" aria-hidden="true">◆</span>
<span>{{.Name}}</span>
<span class="sidebar-nav-item__meta">{{.PostCount}}</span>
</a>
{{end}}
</nav>
</aside>
{{end}}