ui: home carousel height lock + bubble polish

- Home: lock category carousel height to the tallest page so the
  Official Recommendations section below does not jump up when
  swiping to a page with fewer categories.
- CollapsibleText: raise default threshold to 25 lines and tighten
  the spacing between the expand-all button and the timestamp
  (drop the fixed h-8 and use mt-1 instead of mt-1.5).
- formatTime: always render dates as yyyy/m/d HH:mm regardless of
  locale, matching the requested timestamp format.
This commit is contained in:
TerryM
2026-05-30 00:43:54 +08:00
parent c0068e957e
commit d7e2e56cde
4 changed files with 19 additions and 33 deletions

View File

@@ -28,7 +28,7 @@ export function CollapsibleText({
children,
className = "",
wrapperClassName = "",
collapsedLines = 8,
collapsedLines = 25,
}: {
children: ReactNode;
/** Typography classes applied to the text container. */
@@ -110,7 +110,7 @@ export function CollapsibleText({
type="button"
onClick={() => setExpanded((v) => !v)}
aria-expanded={expanded}
className="group mt-1.5 inline-flex h-8 items-center gap-1 text-[13px] font-medium text-ark-gold transition-colors duration-200 hover:text-ark-gold2"
className="group mt-1 inline-flex items-center gap-1 text-[13px] font-medium leading-5 text-ark-gold transition-colors duration-200 hover:text-ark-gold2"
>
<span>{expanded ? t("showLess") : t("showMore")}</span>
<m.span

View File

@@ -1,6 +1,5 @@
import type { ComponentType } from "react";
import type { Post } from "../../types/post";
import { useI18n } from "../../i18n";
import { TextBubble } from "./bubbles/TextBubble";
import { FileDocBubble } from "./bubbles/FileDocBubble";
import { ImageBubble } from "./bubbles/ImageBubble";
@@ -24,7 +23,6 @@ export function pickBubble(post: Post): BubbleComponent {
}
export function MessageBubble({ post }: { post: Post }) {
const { lang } = useI18n();
const Bubble = pickBubble(post);
const isVisual =
Bubble === AlbumBubble ||
@@ -49,7 +47,7 @@ export function MessageBubble({ post }: { post: Post }) {
isVisual ? "px-4 pb-3 pt-3" : "mt-3"
}`}
>
{formatDateTime(post.publishedAt, lang)}
{formatDateTime(post.publishedAt)}
</time>
</article>
</div>

View File

@@ -1,34 +1,17 @@
function localeFor(lang: string): string {
const locales: Record<string, string> = {
zh: "zh-CN",
en: "en-US",
ja: "ja-JP",
ko: "ko-KR",
vi: "vi-VN",
id: "id-ID",
ms: "ms-MY",
};
return locales[lang] ?? "en-US";
function pad2(n: number): string {
return String(n).padStart(2, "0");
}
function formatDate(iso: string, lang: string): string {
function formatDate(iso: string): string {
const d = new Date(iso);
return new Intl.DateTimeFormat(localeFor(lang), {
year: "numeric",
month: lang === "en" ? "short" : "numeric",
day: "numeric",
}).format(d);
return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
}
export function formatTime(iso: string, lang: string): string {
export function formatTime(iso: string): string {
const d = new Date(iso);
return new Intl.DateTimeFormat(localeFor(lang), {
hour: "numeric",
minute: "2-digit",
hour12: lang === "en",
}).format(d);
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
}
export function formatDateTime(iso: string, lang: string): string {
return `${formatDate(iso, lang)} ${formatTime(iso, lang)}`;
export function formatDateTime(iso: string): string {
return `${formatDate(iso)} ${formatTime(iso)}`;
}