feat: SSR 三栏右栏热门帖与 aside widgets
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
|
||||
## A. 浏览与布局
|
||||
|
||||
- [ ] 三栏布局:左导航 / 中 Feed / 右栏小组件
|
||||
- [x] 三栏布局:左导航 / 中 Feed / 右栏小组件 — SSR(桌面;≤900px 隐藏右栏)
|
||||
- [ ] 浅色 / 暗色主题;跟随系统偏好并本地记忆
|
||||
- [ ] 响应式:平板/手机收起侧栏
|
||||
- [ ] 长列表虚拟滚动或等价流畅方案
|
||||
@@ -19,7 +19,7 @@
|
||||
- [x] 板块筛选:全部 + 单板块
|
||||
- [ ] 列表样式可配:`title` | `excerpt` | `thumbnail`
|
||||
- [x] 搜索:关键词、标签、作者、仅标题(`title_only`)— SSR Feed 面板(`/` / `/board/:id`)
|
||||
- [ ] 右栏:热门帖、标签云、最新评论、最新用户、友链(可开关排序)
|
||||
- [x] 右栏:热门帖、标签云、最新评论、最新用户、友链(可开关排序)— SSR 热门固定 + `aside_widgets`;Admin 仅友链侧栏开关
|
||||
- [ ] 登录用户右栏/侧边:签到与抽奖入口(入口暂在 `/profile` 钱包区)
|
||||
- [ ] 下拉刷新(移动端)
|
||||
- [ ] 可选伪静态:`/post/123.html` 等形式(后缀后台可配)
|
||||
|
||||
@@ -86,9 +86,10 @@
|
||||
|
||||
### 2.3 右栏 RightPanel
|
||||
|
||||
- 登录用户:`AsideCheckInStrip`(签到 + 抽奖 + 积分入口)
|
||||
- 热门帖
|
||||
- 可配置 widgets:`tag_cloud` / `recent_comments` / `recent_users` / `friend_links`(顺序与开关来自 settings)
|
||||
- 登录用户:`AsideCheckInStrip`(签到 + 抽奖 + 积分入口)— **未迁**(入口仍在 `/profile`)
|
||||
- 热门帖 — **已迁** SSR(固定块)
|
||||
- 可配置 widgets:`tag_cloud` / `recent_comments` / `recent_users` / `friend_links`(顺序与开关来自 `aside_widgets`)— **已迁** SSR;Admin 完整排序编辑器未迁,友链侧栏开关在 `/admin/friend-links`
|
||||
- 桌面三列;≤900px 隐藏右栏
|
||||
|
||||
### 2.4 移动端
|
||||
|
||||
@@ -184,7 +185,7 @@
|
||||
| Dashboard | 看计数与待办;点进对应列表 |
|
||||
| Boards | 拖拽或数字排序;图标/色板选择;增删改 |
|
||||
| Pages | 列表发布开关;进编辑器写正文;nav/footer 勾选 |
|
||||
| Links | 品牌友链增删;申请通过/拒绝;回链检测开关;nav/footer 开关 — SSR `/admin/friend-links`(aside / 复检按钮未迁) |
|
||||
| Links | 品牌友链增删;申请通过/拒绝;回链检测开关;nav/footer/aside 开关 — SSR `/admin/friend-links`(完整侧栏组件编辑 / 复检按钮未迁) |
|
||||
| Posts | 按状态筛;通过/拒绝;置顶/版顶/精华/锁编/锁评;进回收站恢复/清除 |
|
||||
| Comments | 审核;修订查看;回收站 |
|
||||
| Reports | 处理动作四选一 |
|
||||
|
||||
@@ -92,6 +92,8 @@ web_src/ → public/assets/
|
||||
|
||||
Feed 搜索:`/` / `/board/:id` 面板(`keyword` / `tag` / `author` / `title_only`);排序与分页 URL 保参;顶栏链到 `/#search`。
|
||||
|
||||
友链:`/links`(列表、登录申请/取消、Logo 上传);Admin `/admin/friend-links`(品牌增删、审核、入口开关)。
|
||||
右栏:首页与帖详情三栏;固定热门帖 + `aside_widgets`(标签云 / 最新评论 / 最新用户 / 友链);Admin 友链页可开关侧栏友链。
|
||||
|
||||
友链:`/links`(列表、登录申请/取消、Logo 上传);Admin `/admin/friend-links`(品牌增删、审核、nav/footer/aside 入口开关)。
|
||||
|
||||
Admin:`/admin/dashboard`、`/admin/boards`、`/admin/moderation`、`/admin/settings`(品牌/限流/敏感词/SMTP)、`/admin/friend-links`。
|
||||
@@ -54,6 +54,7 @@ func funcMap() template.FuncMap {
|
||||
"postURL": func(id uint) string {
|
||||
return fmt.Sprintf("/post/%d", id)
|
||||
},
|
||||
"queryEscape": url.QueryEscape,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,13 +61,17 @@ body.j13-body {
|
||||
.j13-nav a:hover { text-decoration: underline; }
|
||||
|
||||
.j13-layout {
|
||||
max-width: 1100px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
grid-template-columns: 200px 1fr 240px;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.j13-layout { grid-template-columns: 200px 1fr; }
|
||||
.j13-aside--right { display: none; }
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.j13-layout { grid-template-columns: 1fr; }
|
||||
}
|
||||
@@ -77,6 +81,9 @@ body.j13-body {
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.j13-aside--right {
|
||||
gap: 1rem;
|
||||
}
|
||||
.j13-aside__link {
|
||||
padding: 0.45rem 0.65rem;
|
||||
border-radius: var(--j13-radius);
|
||||
@@ -90,6 +97,76 @@ body.j13-body {
|
||||
color: var(--j13-accent);
|
||||
}
|
||||
|
||||
.j13-widget__title {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--j13-muted);
|
||||
text-transform: none;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.j13-widget__list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.j13-widget__list a {
|
||||
color: var(--j13-text);
|
||||
text-decoration: none;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.j13-widget__list a:hover { color: var(--j13-accent); }
|
||||
.j13-widget__meta {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
color: var(--j13-muted);
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
.j13-widget__empty {
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
color: var(--j13-muted);
|
||||
}
|
||||
.j13-widget__tags {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem 0.5rem;
|
||||
}
|
||||
.j13-widget__tags a {
|
||||
font-size: 0.8rem;
|
||||
color: var(--j13-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
.j13-widget__tags a:hover { text-decoration: underline; }
|
||||
.j13-widget__count {
|
||||
font-size: 0.7rem;
|
||||
color: var(--j13-muted);
|
||||
margin-left: 0.15rem;
|
||||
}
|
||||
.j13-widget__links a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.j13-widget__logo {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
object-fit: contain;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.j13-widget__more {
|
||||
margin: 0.5rem 0 0;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.j13-widget__more a { color: var(--j13-accent); }
|
||||
|
||||
.j13-main {
|
||||
background: var(--j13-surface);
|
||||
border: 1px solid var(--j13-border);
|
||||
|
||||
@@ -36,15 +36,16 @@ type adminFriendLinkApplyRow struct {
|
||||
|
||||
type adminFriendLinksData struct {
|
||||
AdminChrome
|
||||
BrandLinks []adminFriendLinkBrandRow
|
||||
Applies []adminFriendLinkApplyRow
|
||||
PendingCount int64
|
||||
NavShow bool
|
||||
FooterShow bool
|
||||
ReciprocalCheck bool
|
||||
BrandName string
|
||||
BrandURL string
|
||||
BrandLogo string
|
||||
BrandLinks []adminFriendLinkBrandRow
|
||||
Applies []adminFriendLinkApplyRow
|
||||
PendingCount int64
|
||||
NavShow bool
|
||||
FooterShow bool
|
||||
AsideShow bool
|
||||
ReciprocalCheck bool
|
||||
BrandName string
|
||||
BrandURL string
|
||||
BrandLogo string
|
||||
}
|
||||
|
||||
// AdminFriendLinksGet 友链管理
|
||||
@@ -60,6 +61,7 @@ func (d Deps) renderAdminFriendLinks(ctx *webctx.Context, errMsg string) {
|
||||
AdminChrome: chrome,
|
||||
NavShow: d.Settings.NavShowFriendLinks(),
|
||||
FooterShow: d.Settings.FooterShowFriendLinks(),
|
||||
AsideShow: d.Settings.AsideShowFriendLinks(),
|
||||
ReciprocalCheck: d.Settings.FriendLinkReciprocalCheckEnabled(),
|
||||
}
|
||||
brand := d.Settings.SiteBranding()
|
||||
@@ -105,6 +107,7 @@ func (d Deps) AdminFriendLinksSettingsPost(c *gin.Context) {
|
||||
}
|
||||
_ = d.Settings.SetNavShowFriendLinks(c.PostForm("nav_show") == "1" || c.PostForm("nav_show") == "on")
|
||||
_ = d.Settings.SetFooterShowFriendLinks(c.PostForm("footer_show") == "1" || c.PostForm("footer_show") == "on")
|
||||
_ = d.Settings.SetAsideFriendLinksEnabled(c.PostForm("aside_show") == "1" || c.PostForm("aside_show") == "on")
|
||||
_ = d.Settings.SetFriendLinkReciprocalCheckEnabled(c.PostForm("reciprocal_check") == "1" || c.PostForm("reciprocal_check") == "on")
|
||||
ctx.SetFlash("友链入口设置已保存")
|
||||
ctx.Redirect("/admin/friend-links")
|
||||
|
||||
@@ -34,27 +34,76 @@ type BoardView struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// RightAsideHotPost 右栏热门帖
|
||||
type RightAsideHotPost struct {
|
||||
ID uint
|
||||
Title string
|
||||
}
|
||||
|
||||
// RightAsideTag 右栏标签
|
||||
type RightAsideTag struct {
|
||||
Name string
|
||||
Count int
|
||||
}
|
||||
|
||||
// RightAsideComment 右栏最新评论
|
||||
type RightAsideComment struct {
|
||||
PostID uint
|
||||
Author string
|
||||
Excerpt string
|
||||
PostTitle string
|
||||
}
|
||||
|
||||
// RightAsideUser 右栏最新用户
|
||||
type RightAsideUser struct {
|
||||
ID uint
|
||||
Nickname string
|
||||
}
|
||||
|
||||
// RightAsideFriendLink 右栏友链
|
||||
type RightAsideFriendLink struct {
|
||||
Name string
|
||||
URL string
|
||||
Logo string
|
||||
}
|
||||
|
||||
// RightAsideWidget 按 aside_widgets 顺序的一块(仅已开启)
|
||||
type RightAsideWidget struct {
|
||||
Kind string // tag_cloud | recent_comments | recent_users | friend_links
|
||||
Tags []RightAsideTag
|
||||
Comments []RightAsideComment
|
||||
Users []RightAsideUser
|
||||
FriendLinks []RightAsideFriendLink
|
||||
}
|
||||
|
||||
// RightAsideData 右栏:固定热门 + 可配置 widgets
|
||||
type RightAsideData struct {
|
||||
HotPosts []RightAsideHotPost
|
||||
Widgets []RightAsideWidget
|
||||
}
|
||||
|
||||
// PageChrome 布局公共字段
|
||||
type PageChrome struct {
|
||||
Title string
|
||||
Description string
|
||||
SiteName string
|
||||
Slogan string
|
||||
LogoMark string
|
||||
LoggedIn bool
|
||||
IsAdmin bool
|
||||
ViewerName string
|
||||
Boards []BoardView
|
||||
ActiveBoard uint
|
||||
Path string // 当前请求路径,供侧栏高亮
|
||||
Inner string // 保留字段;入口模板已固定组合,不再动态 template
|
||||
CSRF string
|
||||
Flash string
|
||||
Error string
|
||||
Title string
|
||||
Description string
|
||||
SiteName string
|
||||
Slogan string
|
||||
LogoMark string
|
||||
LoggedIn bool
|
||||
IsAdmin bool
|
||||
ViewerName string
|
||||
Boards []BoardView
|
||||
ActiveBoard uint
|
||||
Path string // 当前请求路径,供侧栏高亮
|
||||
Inner string // 保留字段;入口模板已固定组合,不再动态 template
|
||||
CSRF string
|
||||
Flash string
|
||||
Error string
|
||||
UnreadCount int64 // 登录用户未读私信/通知总数;未登录为 0
|
||||
ViewerPoints int // 登录用户当前积分;未登录为 0
|
||||
ShowFriendLinksNav bool
|
||||
ShowFriendLinksFooter bool
|
||||
RightAside RightAsideData
|
||||
}
|
||||
|
||||
func (d Deps) ctx(c *gin.Context) *webctx.Context {
|
||||
@@ -111,9 +160,73 @@ func (d Deps) chrome(ctx *webctx.Context, title, desc, inner string) PageChrome
|
||||
ViewerPoints: viewerPoints,
|
||||
ShowFriendLinksNav: d.Settings.NavShowFriendLinks(),
|
||||
ShowFriendLinksFooter: d.Settings.FooterShowFriendLinks(),
|
||||
RightAside: d.loadRightAside(brand),
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
rightAsideHotLimit = 5
|
||||
rightAsideTagLimit = 24
|
||||
rightAsideCommentLimit = 8
|
||||
rightAsideUserLimit = 8
|
||||
)
|
||||
|
||||
func (d Deps) loadRightAside(brand services.SiteBranding) RightAsideData {
|
||||
out := RightAsideData{
|
||||
HotPosts: []RightAsideHotPost{},
|
||||
Widgets: []RightAsideWidget{},
|
||||
}
|
||||
if d.Post != nil {
|
||||
if items, err := d.Post.HotPosts(rightAsideHotLimit); err == nil {
|
||||
for _, it := range items {
|
||||
out.HotPosts = append(out.HotPosts, RightAsideHotPost{ID: it.ID, Title: it.Title})
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, w := range d.Settings.AsideWidgets() {
|
||||
if !w.Enabled {
|
||||
continue
|
||||
}
|
||||
block := RightAsideWidget{Kind: w.ID}
|
||||
switch w.ID {
|
||||
case services.AsideWidgetTagCloud:
|
||||
if d.Post != nil {
|
||||
if tags, err := d.Post.PopularTags(rightAsideTagLimit); err == nil {
|
||||
for _, t := range tags {
|
||||
block.Tags = append(block.Tags, RightAsideTag{Name: t.Name, Count: t.Count})
|
||||
}
|
||||
}
|
||||
}
|
||||
case services.AsideWidgetRecentComments:
|
||||
if d.Comment != nil {
|
||||
if list, err := d.Comment.ListRecentPublic(rightAsideCommentLimit); err == nil {
|
||||
for _, c := range list {
|
||||
block.Comments = append(block.Comments, RightAsideComment{
|
||||
PostID: c.PostID, Author: c.Author, Excerpt: c.Excerpt, PostTitle: c.PostTitle,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
case services.AsideWidgetRecentUsers:
|
||||
if d.User != nil {
|
||||
if list, err := d.User.ListRecentRegistered(rightAsideUserLimit); err == nil {
|
||||
for _, u := range list {
|
||||
block.Users = append(block.Users, RightAsideUser{ID: u.ID, Nickname: u.Nickname})
|
||||
}
|
||||
}
|
||||
}
|
||||
case services.AsideWidgetFriendLinks:
|
||||
for _, l := range brand.FriendLinks {
|
||||
block.FriendLinks = append(block.FriendLinks, RightAsideFriendLink{Name: l.Name, URL: l.URL, Logo: l.Logo})
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
out.Widgets = append(out.Widgets, block)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func firstRuneOr(s, fallback string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
|
||||
<label class="j13-check"><input type="checkbox" name="nav_show" value="1"{{if .NavShow}} checked{{end}}/> 导航显示友链入口</label>
|
||||
<label class="j13-check"><input type="checkbox" name="footer_show" value="1"{{if .FooterShow}} checked{{end}}/> 页脚显示友链入口</label>
|
||||
<label class="j13-check"><input type="checkbox" name="aside_show" value="1"{{if .AsideShow}} checked{{end}}/> 侧栏显示友链</label>
|
||||
<label class="j13-check"><input type="checkbox" name="reciprocal_check" value="1"{{if .ReciprocalCheck}} checked{{end}}/> 启用回链检测</label>
|
||||
<button type="submit">保存设置</button>
|
||||
</form>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<main class="j13-main">
|
||||
{{template "home/feed" .}}
|
||||
</main>
|
||||
{{template "shared/right_aside" .}}
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<main class="j13-main">
|
||||
{{template "post/body" .}}
|
||||
</main>
|
||||
{{template "shared/right_aside" .}}
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
{{end}}
|
||||
|
||||
74
templates/shared/right_aside.tmpl
Normal file
74
templates/shared/right_aside.tmpl
Normal file
@@ -0,0 +1,74 @@
|
||||
{{define "shared/right_aside"}}
|
||||
<aside class="j13-aside j13-aside--right" aria-label="侧栏">
|
||||
<section class="j13-widget">
|
||||
<h2 class="j13-widget__title">热门讨论</h2>
|
||||
{{if .RightAside.HotPosts}}
|
||||
<ul class="j13-widget__list">
|
||||
{{range .RightAside.HotPosts}}
|
||||
<li><a href="{{postURL .ID}}">{{.Title}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-widget__empty">暂无热门帖</p>
|
||||
{{end}}
|
||||
</section>
|
||||
{{range .RightAside.Widgets}}
|
||||
<section class="j13-widget">
|
||||
{{if eq .Kind "tag_cloud"}}
|
||||
<h2 class="j13-widget__title">标签</h2>
|
||||
{{if .Tags}}
|
||||
<ul class="j13-widget__tags">
|
||||
{{range .Tags}}
|
||||
<li><a href="/?tag={{queryEscape .Name}}">{{.Name}}</a><span class="j13-widget__count">{{.Count}}</span></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-widget__empty">暂无标签</p>
|
||||
{{end}}
|
||||
{{else if eq .Kind "recent_comments"}}
|
||||
<h2 class="j13-widget__title">最新评论</h2>
|
||||
{{if .Comments}}
|
||||
<ul class="j13-widget__list">
|
||||
{{range .Comments}}
|
||||
<li>
|
||||
<a href="{{postURL .PostID}}">{{.Excerpt}}</a>
|
||||
<span class="j13-widget__meta">{{.Author}} · {{.PostTitle}}</span>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-widget__empty">暂无评论</p>
|
||||
{{end}}
|
||||
{{else if eq .Kind "recent_users"}}
|
||||
<h2 class="j13-widget__title">新用户</h2>
|
||||
{{if .Users}}
|
||||
<ul class="j13-widget__list">
|
||||
{{range .Users}}
|
||||
<li><a href="/user/{{.ID}}">{{.Nickname}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="j13-widget__empty">暂无用户</p>
|
||||
{{end}}
|
||||
{{else if eq .Kind "friend_links"}}
|
||||
<h2 class="j13-widget__title">友链</h2>
|
||||
{{if .FriendLinks}}
|
||||
<ul class="j13-widget__list j13-widget__links">
|
||||
{{range .FriendLinks}}
|
||||
<li>
|
||||
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">
|
||||
{{if .Logo}}<img src="{{.Logo}}" alt="" class="j13-widget__logo"/>{{end}}
|
||||
{{.Name}}
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
<p class="j13-widget__more"><a href="/links">全部友链</a></p>
|
||||
{{else}}
|
||||
<p class="j13-widget__empty">暂无友链 · <a href="/links">去看看</a></p>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</section>
|
||||
{{end}}
|
||||
</aside>
|
||||
{{end}}
|
||||
@@ -61,13 +61,17 @@ body.j13-body {
|
||||
.j13-nav a:hover { text-decoration: underline; }
|
||||
|
||||
.j13-layout {
|
||||
max-width: 1100px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
grid-template-columns: 200px 1fr 240px;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.j13-layout { grid-template-columns: 200px 1fr; }
|
||||
.j13-aside--right { display: none; }
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.j13-layout { grid-template-columns: 1fr; }
|
||||
}
|
||||
@@ -77,6 +81,9 @@ body.j13-body {
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.j13-aside--right {
|
||||
gap: 1rem;
|
||||
}
|
||||
.j13-aside__link {
|
||||
padding: 0.45rem 0.65rem;
|
||||
border-radius: var(--j13-radius);
|
||||
@@ -90,6 +97,76 @@ body.j13-body {
|
||||
color: var(--j13-accent);
|
||||
}
|
||||
|
||||
.j13-widget__title {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--j13-muted);
|
||||
text-transform: none;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.j13-widget__list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.j13-widget__list a {
|
||||
color: var(--j13-text);
|
||||
text-decoration: none;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.j13-widget__list a:hover { color: var(--j13-accent); }
|
||||
.j13-widget__meta {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
color: var(--j13-muted);
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
.j13-widget__empty {
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
color: var(--j13-muted);
|
||||
}
|
||||
.j13-widget__tags {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem 0.5rem;
|
||||
}
|
||||
.j13-widget__tags a {
|
||||
font-size: 0.8rem;
|
||||
color: var(--j13-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
.j13-widget__tags a:hover { text-decoration: underline; }
|
||||
.j13-widget__count {
|
||||
font-size: 0.7rem;
|
||||
color: var(--j13-muted);
|
||||
margin-left: 0.15rem;
|
||||
}
|
||||
.j13-widget__links a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.j13-widget__logo {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
object-fit: contain;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.j13-widget__more {
|
||||
margin: 0.5rem 0 0;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.j13-widget__more a { color: var(--j13-accent); }
|
||||
|
||||
.j13-main {
|
||||
background: var(--j13-surface);
|
||||
border: 1px solid var(--j13-border);
|
||||
|
||||
Reference in New Issue
Block a user