feat: 首页对齐 main SPA 草绿壳与 Feed v2
顶栏搜索胶囊/发帖绿钮/Ctrl+K,侧栏板块色槽,列表 post-row--v2 与 SPA 同密度。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -44,9 +44,11 @@ type SitePageLink struct {
|
||||
|
||||
// BoardView 侧栏
|
||||
type BoardView struct {
|
||||
ID uint
|
||||
Name string
|
||||
Href string
|
||||
ID uint
|
||||
Name string
|
||||
Href string
|
||||
PostCount int
|
||||
ColorSlot int // 0–7 板块色槽
|
||||
}
|
||||
|
||||
// RightAsideHotPost 右栏热门帖
|
||||
@@ -122,6 +124,8 @@ type PageChrome struct {
|
||||
LoggedIn bool
|
||||
IsAdmin bool
|
||||
ViewerName string
|
||||
ViewerAvatar string
|
||||
ViewerMark string
|
||||
Boards []BoardView
|
||||
ActiveBoard uint
|
||||
Path string // 当前请求路径,供侧栏高亮
|
||||
@@ -158,19 +162,30 @@ func (d Deps) chrome(ctx *webctx.Context, title, desc, inner string) PageChrome
|
||||
name = ctx.Doer.Username
|
||||
}
|
||||
}
|
||||
boards, _ := d.Board.List()
|
||||
boards, _ := d.Board.ListWithStats()
|
||||
bv := make([]BoardView, 0, len(boards))
|
||||
pl := d.permalink()
|
||||
for _, b := range boards {
|
||||
bv = append(bv, BoardView{ID: b.ID, Name: b.Name, Href: pl.BoardPath(b.ID)})
|
||||
slot := b.ColorIndex
|
||||
if slot < 0 {
|
||||
slot = int(b.ID % 8)
|
||||
}
|
||||
bv = append(bv, BoardView{
|
||||
ID: b.ID, Name: b.Name, Href: pl.BoardPath(b.ID),
|
||||
PostCount: b.PostCount, ColorSlot: slot % 8,
|
||||
})
|
||||
}
|
||||
var unread int64
|
||||
if ctx.IsSigned() && d.Message != nil {
|
||||
unread, _ = d.Message.UnreadCount(ctx.UserID())
|
||||
}
|
||||
viewerPoints := 0
|
||||
viewerAvatar := ""
|
||||
viewerMark := "我"
|
||||
if ctx.IsSigned() && ctx.Doer != nil {
|
||||
viewerPoints = ctx.Doer.Points
|
||||
viewerAvatar = strings.TrimSpace(ctx.Doer.Avatar)
|
||||
viewerMark = firstRuneOr(name, "我")
|
||||
}
|
||||
path := ""
|
||||
if ctx.C != nil && ctx.C.Request != nil && ctx.C.Request.URL != nil {
|
||||
@@ -195,6 +210,8 @@ func (d Deps) chrome(ctx *webctx.Context, title, desc, inner string) PageChrome
|
||||
LoggedIn: ctx.IsSigned(),
|
||||
IsAdmin: ctx.IsAdmin(),
|
||||
ViewerName: name,
|
||||
ViewerAvatar: viewerAvatar,
|
||||
ViewerMark: viewerMark,
|
||||
Boards: bv,
|
||||
Path: path,
|
||||
Inner: inner,
|
||||
|
||||
@@ -148,40 +148,52 @@ func Register(r *gin.Engine, deps Deps, authMW *auth.AuthMiddleware) {
|
||||
// HomePageData Feed
|
||||
type HomePageData struct {
|
||||
PageChrome
|
||||
BoardName string
|
||||
Sort string
|
||||
Keyword string
|
||||
Tag string
|
||||
Author string
|
||||
TitleOnly bool
|
||||
HasSearch bool
|
||||
SearchError string
|
||||
Posts []PostListItem
|
||||
Page int
|
||||
PrevPage int
|
||||
NextPage int
|
||||
HasPrev bool
|
||||
HasMore bool
|
||||
BoardName string
|
||||
Sort string
|
||||
Keyword string
|
||||
Tag string
|
||||
Author string
|
||||
TitleOnly bool
|
||||
HasSearch bool
|
||||
SearchError string
|
||||
FeedListStyle string // title|excerpt|thumbnail
|
||||
ShowExcerpt bool
|
||||
Posts []PostListItem
|
||||
Page int
|
||||
PrevPage int
|
||||
NextPage int
|
||||
HasPrev bool
|
||||
HasMore bool
|
||||
}
|
||||
|
||||
// PostListItem 列表项
|
||||
// PostListItem 列表项(对齐 main SPA post-row--v2)
|
||||
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
|
||||
ID uint
|
||||
Title string
|
||||
Href string
|
||||
AuthorID uint
|
||||
AuthorName string
|
||||
AuthorHref string
|
||||
AvatarURL string
|
||||
AuthorMark string
|
||||
BoardID uint
|
||||
BoardName string
|
||||
BoardHref string
|
||||
BoardColorSlot int
|
||||
ShowBoardBadge bool
|
||||
Excerpt string
|
||||
ThumbURL string
|
||||
Pinned bool
|
||||
BoardPinned bool
|
||||
Featured bool
|
||||
CommentCount int
|
||||
LikeCount int
|
||||
ViewCount int
|
||||
CreatedLabel string
|
||||
LastReplyLabel string
|
||||
LastReplyName string
|
||||
LastReplyHref string
|
||||
ShowLastReply bool
|
||||
}
|
||||
|
||||
// FormAction 搜索表单提交路径(当前 Feed)
|
||||
@@ -274,19 +286,24 @@ func (d Deps) Home(c *gin.Context) {
|
||||
chrome.Title = boardName + " · " + chrome.SiteName
|
||||
}
|
||||
|
||||
feedStyle := d.Settings.FeedListStyle()
|
||||
showExcerpt := feedStyle == "excerpt" || feedStyle == "thumbnail"
|
||||
|
||||
data := HomePageData{
|
||||
PageChrome: chrome,
|
||||
BoardName: boardName,
|
||||
Sort: sort,
|
||||
Keyword: keyword,
|
||||
Tag: tag,
|
||||
Author: author,
|
||||
TitleOnly: titleOnly,
|
||||
HasSearch: hasSearch,
|
||||
Page: page,
|
||||
PrevPage: page - 1,
|
||||
NextPage: page + 1,
|
||||
HasPrev: page > 1,
|
||||
PageChrome: chrome,
|
||||
BoardName: boardName,
|
||||
Sort: sort,
|
||||
Keyword: keyword,
|
||||
Tag: tag,
|
||||
Author: author,
|
||||
TitleOnly: titleOnly,
|
||||
HasSearch: hasSearch,
|
||||
FeedListStyle: feedStyle,
|
||||
ShowExcerpt: showExcerpt,
|
||||
Page: page,
|
||||
PrevPage: page - 1,
|
||||
NextPage: page + 1,
|
||||
HasPrev: page > 1,
|
||||
}
|
||||
|
||||
listKW := keyword
|
||||
@@ -333,14 +350,29 @@ func (d Deps) Home(c *gin.Context) {
|
||||
authorName = it.User.Username
|
||||
}
|
||||
bname := ""
|
||||
boardHref := ""
|
||||
boardSlot := 0
|
||||
if it.Board.ID > 0 {
|
||||
bname = it.Board.Name
|
||||
boardHref = pl.BoardPath(it.Board.ID)
|
||||
boardSlot = it.Board.ColorIndex
|
||||
if boardSlot < 0 {
|
||||
boardSlot = int(it.Board.ID % 8)
|
||||
}
|
||||
boardSlot = boardSlot % 8
|
||||
}
|
||||
excerptSrc := strings.TrimSpace(it.ContentPlain)
|
||||
if excerptSrc == "" {
|
||||
excerptSrc = services.ExcerptFromHTML(it.Content, 100)
|
||||
} else {
|
||||
excerptSrc = services.TruncateRunes(excerptSrc, 100)
|
||||
excerptSrc := ""
|
||||
thumbURL := ""
|
||||
if showExcerpt {
|
||||
excerptSrc = strings.TrimSpace(it.ContentPlain)
|
||||
if excerptSrc == "" {
|
||||
excerptSrc = services.ExcerptFromHTML(it.Content, 60)
|
||||
} else {
|
||||
excerptSrc = services.TruncateRunes(excerptSrc, 60)
|
||||
}
|
||||
}
|
||||
if feedStyle == "thumbnail" {
|
||||
thumbURL = services.FirstImageURL(it.Content)
|
||||
}
|
||||
avatar := strings.TrimSpace(it.User.Avatar)
|
||||
authorID := it.UserID
|
||||
@@ -348,14 +380,44 @@ func (d Deps) Home(c *gin.Context) {
|
||||
if authorID > 0 {
|
||||
authorHref = pl.UserPath(authorID)
|
||||
}
|
||||
createdLabel := formatRelativeTime(it.CreatedAt)
|
||||
if sort == "reply" && it.LastReplyAt == nil {
|
||||
createdLabel = "暂无回复"
|
||||
}
|
||||
lastReplyName := ""
|
||||
lastReplyHref := ""
|
||||
lastReplyLabel := ""
|
||||
showLast := false
|
||||
if it.LastReplyAt != nil {
|
||||
showLast = true
|
||||
lastReplyLabel = formatRelativeTime(*it.LastReplyAt)
|
||||
if it.LastReplyUser != nil {
|
||||
lastReplyName = strings.TrimSpace(it.LastReplyUser.Nickname)
|
||||
if lastReplyName == "" {
|
||||
lastReplyName = it.LastReplyUser.Username
|
||||
}
|
||||
if it.LastReplyUser.ID > 0 {
|
||||
lastReplyHref = pl.UserPath(it.LastReplyUser.ID)
|
||||
}
|
||||
} else {
|
||||
lastReplyName = strings.TrimSpace(it.LastReplyGuestNick)
|
||||
}
|
||||
if lastReplyName == "" {
|
||||
showLast = false
|
||||
}
|
||||
}
|
||||
posts = append(posts, PostListItem{
|
||||
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,
|
||||
BoardID: it.BoardID, BoardName: bname, BoardHref: boardHref,
|
||||
BoardColorSlot: boardSlot, ShowBoardBadge: boardID == 0 && it.Board.ID > 0,
|
||||
Excerpt: excerptSrc, ThumbURL: thumbURL,
|
||||
Pinned: it.Pinned, BoardPinned: it.BoardPinned, Featured: it.Featured,
|
||||
CommentCount: it.CommentCount, LikeCount: it.LikeCount, ViewCount: it.ViewCount,
|
||||
CreatedLabel: formatRelativeTime(it.CreatedAt),
|
||||
CreatedLabel: createdLabel,
|
||||
LastReplyLabel: lastReplyLabel, LastReplyName: lastReplyName,
|
||||
LastReplyHref: lastReplyHref, ShowLastReply: showLast,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user