terry-staging #11
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)}`;
|
||||
}
|
||||
|
||||
@@ -137,10 +137,15 @@ export function Home() {
|
||||
for (let index = 0; index < figmaOrderedCategories.length; index += 9) {
|
||||
categoryPages.push(figmaOrderedCategories.slice(index, index + 9));
|
||||
}
|
||||
const activeCategoryCount = categoryPages[activeCategoryPage]?.length ?? 0;
|
||||
const activeCategoryRows = Math.ceil(activeCategoryCount / 3);
|
||||
// Use the tallest page so the carousel height doesn't shrink between
|
||||
// pages — otherwise the section below jumps up when swiping to a page
|
||||
// with fewer categories.
|
||||
const maxCategoryRows = categoryPages.reduce(
|
||||
(max, page) => Math.max(max, Math.ceil(page.length / 3)),
|
||||
0,
|
||||
);
|
||||
const mobileCategoryHeight =
|
||||
activeCategoryRows * 88 + Math.max(0, activeCategoryRows - 1) * 8;
|
||||
maxCategoryRows * 88 + Math.max(0, maxCategoryRows - 1) * 8;
|
||||
|
||||
useEffect(() => {
|
||||
const row = categoryRowRef.current;
|
||||
|
||||
Reference in New Issue
Block a user