fix: 帖行评论数勿贴右缘,手机 SSR 顶栏/页脚与 React 同构
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -520,10 +520,10 @@ export default function MainLayout() {
|
|||||||
<div className="app-frame">
|
<div className="app-frame">
|
||||||
<header className="app-header">
|
<header className="app-header">
|
||||||
<div className="header-inner">
|
<div className="header-inner">
|
||||||
{isMobile && !isCompose && (
|
{!isCompose && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="header-icon-btn"
|
className="header-icon-btn header-menu-btn"
|
||||||
onClick={openSidebar}
|
onClick={openSidebar}
|
||||||
aria-label="打开导航菜单"
|
aria-label="打开导航菜单"
|
||||||
aria-expanded={sidebarOpen}
|
aria-expanded={sidebarOpen}
|
||||||
@@ -536,7 +536,7 @@ export default function MainLayout() {
|
|||||||
{/* 任意页点 Logo:回首页并强制刷新,不展示会话缓存 */}
|
{/* 任意页点 Logo:回首页并强制刷新,不展示会话缓存 */}
|
||||||
<button type="button" className="header-brand" onClick={() => navigateFeed(nav, '/', { refresh: true })}>
|
<button type="button" className="header-brand" onClick={() => navigateFeed(nav, '/', { refresh: true })}>
|
||||||
<SiteBrandMark branding={branding} className="header-logo-mark" />
|
<SiteBrandMark branding={branding} className="header-logo-mark" />
|
||||||
{!isMobile && <span className="header-logo-text">{branding.name}</span>}
|
<span className="header-logo-text">{branding.name}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{!isCompose && isMobile && (
|
{!isCompose && isMobile && (
|
||||||
@@ -621,7 +621,7 @@ export default function MainLayout() {
|
|||||||
aria-label="发帖"
|
aria-label="发帖"
|
||||||
>
|
>
|
||||||
<Plus size={16} aria-hidden />
|
<Plus size={16} aria-hidden />
|
||||||
{!isMobile && <span>发帖</span>}
|
<span className="header-compose-btn__label">发帖</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -641,17 +641,15 @@ export default function MainLayout() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isMobile && (
|
<button
|
||||||
<button
|
|
||||||
type="button"
|
type="button"
|
||||||
className="header-icon-btn"
|
className="header-icon-btn header-theme-btn"
|
||||||
onClick={toggle}
|
onClick={toggle}
|
||||||
aria-label={theme === 'light' ? '切换暗色模式' : '切换亮色模式'}
|
aria-label={theme === 'light' ? '切换暗色模式' : '切换亮色模式'}
|
||||||
title={theme === 'light' ? '切换暗色模式' : '切换亮色模式'}
|
title={theme === 'light' ? '切换暗色模式' : '切换亮色模式'}
|
||||||
>
|
>
|
||||||
{theme === 'light' ? <Moon size={18} aria-hidden /> : <Sun size={18} aria-hidden />}
|
{theme === 'light' ? <Moon size={18} aria-hidden /> : <Sun size={18} aria-hidden />}
|
||||||
</button>
|
</button>
|
||||||
)}
|
|
||||||
|
|
||||||
{authLoading ? (
|
{authLoading ? (
|
||||||
<span className="header-auth-slot header-auth-slot--loading" aria-hidden />
|
<span className="header-auth-slot header-auth-slot--loading" aria-hidden />
|
||||||
|
|||||||
@@ -345,6 +345,16 @@ html.dark .top-progress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
/* 桌面:只保留壳层贴底页脚,隐藏列表内流入页脚 */
|
||||||
|
.post-list-scroll > .site-footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.header-menu-btn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.admin-brand-sections > .admin-settings-section {
|
.admin-brand-sections > .admin-settings-section {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
@@ -1974,10 +1984,17 @@ html.dark .ssr-theme-icon--sun {
|
|||||||
.sidebar { display: none; }
|
.sidebar { display: none; }
|
||||||
.header-inner { padding: 0 12px; gap: 8px; }
|
.header-inner { padding: 0 12px; gap: 8px; }
|
||||||
.header-brand { flex-shrink: 0; }
|
.header-brand { flex-shrink: 0; }
|
||||||
|
.header-logo-text { display: none; }
|
||||||
|
.header-menu-btn { display: inline-flex; }
|
||||||
|
.header-theme-btn { display: none; }
|
||||||
|
.header-compose-btn__label { display: none; }
|
||||||
.header-search-wrap { max-width: none; }
|
.header-search-wrap { max-width: none; }
|
||||||
.header-compose-btn { width: 34px; padding: 0; justify-content: center; }
|
.header-compose-btn { width: 34px; padding: 0; justify-content: center; }
|
||||||
.header-action-group { gap: 4px; }
|
.header-action-group { gap: 4px; }
|
||||||
|
|
||||||
|
/* 手机:藏壳层贴底页脚(列表内 InFlow 负责) */
|
||||||
|
.app-frame > .site-footer { display: none; }
|
||||||
|
|
||||||
.post-search-field__input {
|
.post-search-field__input {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
@@ -3144,7 +3161,7 @@ a.post-row {
|
|||||||
.post-row--v2 .post-meta {
|
.post-row--v2 .post-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: flex-start;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -3158,7 +3175,7 @@ a.post-row {
|
|||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
flex: 1;
|
flex: 0 1 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3354,6 +3371,8 @@ a.post-row {
|
|||||||
|
|
||||||
.post-row--v2 .post-stats {
|
.post-row--v2 .post-stats {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-row--v2 .post-stat {
|
.post-row--v2 .post-stat {
|
||||||
|
|||||||
@@ -342,6 +342,10 @@ func renderHomeSSRHTML(data *homeSSRData) string {
|
|||||||
b.WriteString(`<div class="app-shell ssr-home"><div class="app-frame">`)
|
b.WriteString(`<div class="app-shell ssr-home"><div class="app-frame">`)
|
||||||
|
|
||||||
b.WriteString(`<header class="app-header"><div class="header-inner">`)
|
b.WriteString(`<header class="app-header"><div class="header-inner">`)
|
||||||
|
// 手机端汉堡:桌面 CSS 隐藏;hydrate 后由 React 接管点击
|
||||||
|
b.WriteString(`<button type="button" class="header-icon-btn header-menu-btn" aria-label="打开导航菜单" title="导航">`)
|
||||||
|
b.WriteString(ssrIconMenu())
|
||||||
|
b.WriteString(`</button>`)
|
||||||
b.WriteString(`<a class="header-brand" href="/">`)
|
b.WriteString(`<a class="header-brand" href="/">`)
|
||||||
if logo := strings.TrimSpace(boot.Branding.Logo); logo != "" {
|
if logo := strings.TrimSpace(boot.Branding.Logo); logo != "" {
|
||||||
b.WriteString(`<img class="header-logo-mark" src="` + html.EscapeString(logo) + `" alt=""/>`)
|
b.WriteString(`<img class="header-logo-mark" src="` + html.EscapeString(logo) + `" alt=""/>`)
|
||||||
@@ -366,11 +370,11 @@ func renderHomeSSRHTML(data *homeSSRData) string {
|
|||||||
}
|
}
|
||||||
b.WriteString(`<a class="header-compose-btn" href="` + composeHref + `" aria-label="发帖">`)
|
b.WriteString(`<a class="header-compose-btn" href="` + composeHref + `" aria-label="发帖">`)
|
||||||
b.WriteString(ssrIconPlus())
|
b.WriteString(ssrIconPlus())
|
||||||
b.WriteString(`<span>发帖</span></a>`)
|
b.WriteString(`<span class="header-compose-btn__label">发帖</span></a>`)
|
||||||
|
|
||||||
b.WriteString(`<div class="header-action-group">`)
|
b.WriteString(`<div class="header-action-group">`)
|
||||||
// 主题:双图标 + CSS,配合 documentElement.dark
|
// 主题:双图标 + CSS,配合 documentElement.dark;手机顶栏 CSS 隐藏
|
||||||
b.WriteString(`<button type="button" class="header-icon-btn" aria-label="切换主题" title="切换主题">`)
|
b.WriteString(`<button type="button" class="header-icon-btn header-theme-btn" aria-label="切换主题" title="切换主题">`)
|
||||||
b.WriteString(`<span class="ssr-theme-icon ssr-theme-icon--moon">` + ssrIconMoon() + `</span>`)
|
b.WriteString(`<span class="ssr-theme-icon ssr-theme-icon--moon">` + ssrIconMoon() + `</span>`)
|
||||||
b.WriteString(`<span class="ssr-theme-icon ssr-theme-icon--sun">` + ssrIconSun() + `</span>`)
|
b.WriteString(`<span class="ssr-theme-icon ssr-theme-icon--sun">` + ssrIconSun() + `</span>`)
|
||||||
b.WriteString(`</button>`)
|
b.WriteString(`</button>`)
|
||||||
@@ -593,7 +597,10 @@ func writeSSRFeed(b *strings.Builder, boot homeBootPayload, meta homeSSRMeta) {
|
|||||||
writeSSRPostRow(b, &boot.Posts[i], boot.BoardID, meta.permalink, boot.Sort, titleOnly, needExcerpt, needThumb)
|
writeSSRPostRow(b, &boot.Posts[i], boot.BoardID, meta.permalink, boot.Sort, titleOnly, needExcerpt, needThumb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.WriteString(`</div></div></div></div>`)
|
b.WriteString(`</div>`)
|
||||||
|
// 手机端流入页脚(桌面 CSS 隐藏);壳层贴底页脚见 writeSSRFooter
|
||||||
|
writeSSRFooter(b, boot, meta)
|
||||||
|
b.WriteString(`</div></div></div>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ssrFilterQuery(boot homeBootPayload) url.Values {
|
func ssrFilterQuery(boot homeBootPayload) url.Values {
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ func ssrIconPlus() string {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ssrIconMenu() string {
|
||||||
|
return ssrSVG(18,
|
||||||
|
`<path d="M4 5h16"/>`,
|
||||||
|
`<path d="M4 12h16"/>`,
|
||||||
|
`<path d="M4 19h16"/>`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func ssrIconMoon() string {
|
func ssrIconMoon() string {
|
||||||
return ssrSVG(18,
|
return ssrSVG(18,
|
||||||
`<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>`,
|
`<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>`,
|
||||||
|
|||||||
Reference in New Issue
Block a user