fix: 书库阅读页/帖子详情页/SiteDocMasthead/TOC 等前端细节修复
This commit is contained in:
@@ -16,7 +16,7 @@ import {
|
|||||||
groupSections,
|
groupSections,
|
||||||
type ChapterNav,
|
type ChapterNav,
|
||||||
} from "@/lib/librarySections";
|
} from "@/lib/librarySections";
|
||||||
import { extractToc, estimateReadingMinutes, markdownHeadingToc, buildTocFromSegments } from "@/lib/toc";
|
import { extractToc, estimateReadingMinutes, formatReadingDuration, markdownHeadingToc, buildTocFromSegments } from "@/lib/toc";
|
||||||
import { splitContentSegments } from "@/lib/directiveBlocks";
|
import { splitContentSegments } from "@/lib/directiveBlocks";
|
||||||
import { wrapImplicitEntries } from "@/lib/entryBlocks";
|
import { wrapImplicitEntries } from "@/lib/entryBlocks";
|
||||||
import PostToc, { type TocItem } from "@/components/PostToc";
|
import PostToc, { type TocItem } from "@/components/PostToc";
|
||||||
@@ -223,7 +223,7 @@ export default async function LibraryReadPage({ params, searchParams }: PageProp
|
|||||||
{current.title}
|
{current.title}
|
||||||
</p>
|
</p>
|
||||||
<p className="meta mt-0.5 text-[10.5px] leading-tight">
|
<p className="meta mt-0.5 text-[10.5px] leading-tight">
|
||||||
第 {nav.index + 1} / {nav.total} 章 · 约 {chapterMinutes} 分钟
|
第 {nav.index + 1} / {nav.total} 章 · 约 {formatReadingDuration(chapterMinutes)} 读完
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@@ -265,7 +265,7 @@ export default async function LibraryReadPage({ params, searchParams }: PageProp
|
|||||||
<header>
|
<header>
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<p className="meta text-[12px]">
|
<p className="meta text-[12px]">
|
||||||
第 {nav.index + 1} / {nav.total} 章 · 约 {chapterMinutes} 分钟
|
第 {nav.index + 1} / {nav.total} 章 · 约 {formatReadingDuration(chapterMinutes)} 读完
|
||||||
</p>
|
</p>
|
||||||
<BookSearch
|
<BookSearch
|
||||||
slug={d.slug}
|
slug={d.slug}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import AcceptedAnswerCard from "@/components/AcceptedAnswerCard";
|
|||||||
import { canModerateBoard } from "@/lib/roles";
|
import { canModerateBoard } from "@/lib/roles";
|
||||||
import { IconComment, IconEye } from "@/components/Icons";
|
import { IconComment, IconEye } from "@/components/Icons";
|
||||||
import { normalizePostType, postTypeLabel, contentAccessLabel, typeStatusLabel, typeStatusClass } from "@/lib/postMeta";
|
import { normalizePostType, postTypeLabel, contentAccessLabel, typeStatusLabel, typeStatusClass } from "@/lib/postMeta";
|
||||||
import { extractToc, estimateReadingMinutes, markdownHeadingToc } from "@/lib/toc";
|
import { extractToc, estimateReadingMinutes, formatReadingDuration, markdownHeadingToc } from "@/lib/toc";
|
||||||
import { requestCanonical } from "@/lib/canonicalMeta";
|
import { requestCanonical } from "@/lib/canonicalMeta";
|
||||||
import { absoluteCanonical, canonicalPage } from "@/lib/siteUrl";
|
import { absoluteCanonical, canonicalPage } from "@/lib/siteUrl";
|
||||||
import { postPath, userPath, type UrlStyle } from "@/lib/urlStyle";
|
import { postPath, userPath, type UrlStyle } from "@/lib/urlStyle";
|
||||||
@@ -450,7 +450,7 @@ export default async function PostDetailPage({ params, searchParams }: PageProps
|
|||||||
<p className="truncate text-[13px] font-bold leading-tight" style={{ color: "var(--ink)" }}>
|
<p className="truncate text-[13px] font-bold leading-tight" style={{ color: "var(--ink)" }}>
|
||||||
{post.title}
|
{post.title}
|
||||||
</p>
|
</p>
|
||||||
<p className="meta mt-0.5 text-[10.5px] leading-tight">约 {readingMinutes} 分钟读完</p>
|
<p className="meta mt-0.5 text-[10.5px] leading-tight">约 {formatReadingDuration(readingMinutes)} 读完</p>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
left={leftRailNode ? { label: "导航", content: leftRailNode } : undefined}
|
left={leftRailNode ? { label: "导航", content: leftRailNode } : undefined}
|
||||||
@@ -599,8 +599,8 @@ export default async function PostDetailPage({ params, searchParams }: PageProps
|
|||||||
<IconComment size={14} /> {post.comment_count} 评论
|
<IconComment size={14} /> {post.comment_count} 评论
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
<span className="inline-flex items-center gap-1.5" aria-label={`阅读约需 ${readingMinutes} 分钟`}>
|
<span className="inline-flex items-center gap-1.5" aria-label={`阅读约需 ${formatReadingDuration(readingMinutes)}`}>
|
||||||
<Clock size={14} /> 约 {readingMinutes} 分钟读完
|
<Clock size={14} /> 约 {formatReadingDuration(readingMinutes)} 读完
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="meta w-full text-[12px] sm:w-auto sm:ml-auto">
|
<p className="meta w-full text-[12px] sm:w-auto sm:ml-auto">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { Clock } from "lucide-react";
|
import { Clock } from "lucide-react";
|
||||||
import { formatDate } from "@/lib/format";
|
import { formatDate } from "@/lib/format";
|
||||||
|
import { formatReadingDuration } from "@/lib/toc";
|
||||||
|
|
||||||
function formatDateTime(dateStr: string) {
|
function formatDateTime(dateStr: string) {
|
||||||
return new Date(dateStr).toLocaleString("zh-CN", {
|
return new Date(dateStr).toLocaleString("zh-CN", {
|
||||||
@@ -83,9 +84,9 @@ export default function SiteDocMasthead({
|
|||||||
{readingMinutes != null ? (
|
{readingMinutes != null ? (
|
||||||
<span
|
<span
|
||||||
className="meta inline-flex items-center gap-1.5 text-[12.5px] sm:ml-auto"
|
className="meta inline-flex items-center gap-1.5 text-[12.5px] sm:ml-auto"
|
||||||
aria-label={`阅读约需 ${readingMinutes} 分钟`}
|
aria-label={`阅读约需 ${formatReadingDuration(readingMinutes)}`}
|
||||||
>
|
>
|
||||||
<Clock size={13} /> 约 {readingMinutes} 分钟读完
|
<Clock size={13} /> 约 {formatReadingDuration(readingMinutes)} 读完
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -167,3 +167,11 @@ export function estimateReadingMinutes(text: string, fallbackLen = 0): number {
|
|||||||
const len = text.trim().length > 0 ? text.trim().length : fallbackLen;
|
const len = text.trim().length > 0 ? text.trim().length : fallbackLen;
|
||||||
return Math.max(1, Math.ceil(len / 400));
|
return Math.max(1, Math.ceil(len / 400));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 阅读时长展示:≥60 分钟换算成「X 小时 Y 分钟」,避免大分钟数需口算 */
|
||||||
|
export function formatReadingDuration(minutes: number): string {
|
||||||
|
if (minutes < 60) return `${minutes} 分钟`;
|
||||||
|
const h = Math.floor(minutes / 60);
|
||||||
|
const m = minutes % 60;
|
||||||
|
return m > 0 ? `${h} 小时 ${m} 分钟` : `${h} 小时`;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user