terry-staging #11
@@ -28,7 +28,7 @@ export function CollapsibleText({
|
|||||||
children,
|
children,
|
||||||
className = "",
|
className = "",
|
||||||
wrapperClassName = "",
|
wrapperClassName = "",
|
||||||
collapsedLines = 8,
|
collapsedLines = 25,
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
/** Typography classes applied to the text container. */
|
/** Typography classes applied to the text container. */
|
||||||
@@ -110,7 +110,7 @@ export function CollapsibleText({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => setExpanded((v) => !v)}
|
onClick={() => setExpanded((v) => !v)}
|
||||||
aria-expanded={expanded}
|
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>
|
<span>{expanded ? t("showLess") : t("showMore")}</span>
|
||||||
<m.span
|
<m.span
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { ComponentType } from "react";
|
import type { ComponentType } from "react";
|
||||||
import type { Post } from "../../types/post";
|
import type { Post } from "../../types/post";
|
||||||
import { useI18n } from "../../i18n";
|
|
||||||
import { TextBubble } from "./bubbles/TextBubble";
|
import { TextBubble } from "./bubbles/TextBubble";
|
||||||
import { FileDocBubble } from "./bubbles/FileDocBubble";
|
import { FileDocBubble } from "./bubbles/FileDocBubble";
|
||||||
import { ImageBubble } from "./bubbles/ImageBubble";
|
import { ImageBubble } from "./bubbles/ImageBubble";
|
||||||
@@ -24,7 +23,6 @@ export function pickBubble(post: Post): BubbleComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function MessageBubble({ post }: { post: Post }) {
|
export function MessageBubble({ post }: { post: Post }) {
|
||||||
const { lang } = useI18n();
|
|
||||||
const Bubble = pickBubble(post);
|
const Bubble = pickBubble(post);
|
||||||
const isVisual =
|
const isVisual =
|
||||||
Bubble === AlbumBubble ||
|
Bubble === AlbumBubble ||
|
||||||
@@ -49,7 +47,7 @@ export function MessageBubble({ post }: { post: Post }) {
|
|||||||
isVisual ? "px-4 pb-3 pt-3" : "mt-3"
|
isVisual ? "px-4 pb-3 pt-3" : "mt-3"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{formatDateTime(post.publishedAt, lang)}
|
{formatDateTime(post.publishedAt)}
|
||||||
</time>
|
</time>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,34 +1,17 @@
|
|||||||
function localeFor(lang: string): string {
|
function pad2(n: number): string {
|
||||||
const locales: Record<string, string> = {
|
return String(n).padStart(2, "0");
|
||||||
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 formatDate(iso: string, lang: string): string {
|
function formatDate(iso: string): string {
|
||||||
const d = new Date(iso);
|
const d = new Date(iso);
|
||||||
return new Intl.DateTimeFormat(localeFor(lang), {
|
return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
|
||||||
year: "numeric",
|
|
||||||
month: lang === "en" ? "short" : "numeric",
|
|
||||||
day: "numeric",
|
|
||||||
}).format(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatTime(iso: string, lang: string): string {
|
export function formatTime(iso: string): string {
|
||||||
const d = new Date(iso);
|
const d = new Date(iso);
|
||||||
return new Intl.DateTimeFormat(localeFor(lang), {
|
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
||||||
hour: "numeric",
|
|
||||||
minute: "2-digit",
|
|
||||||
hour12: lang === "en",
|
|
||||||
}).format(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatDateTime(iso: string, lang: string): string {
|
export function formatDateTime(iso: string): string {
|
||||||
return `${formatDate(iso, lang)} ${formatTime(iso, lang)}`;
|
return `${formatDate(iso)} ${formatTime(iso)}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,10 +137,15 @@ export function Home() {
|
|||||||
for (let index = 0; index < figmaOrderedCategories.length; index += 9) {
|
for (let index = 0; index < figmaOrderedCategories.length; index += 9) {
|
||||||
categoryPages.push(figmaOrderedCategories.slice(index, index + 9));
|
categoryPages.push(figmaOrderedCategories.slice(index, index + 9));
|
||||||
}
|
}
|
||||||
const activeCategoryCount = categoryPages[activeCategoryPage]?.length ?? 0;
|
// Use the tallest page so the carousel height doesn't shrink between
|
||||||
const activeCategoryRows = Math.ceil(activeCategoryCount / 3);
|
// 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 =
|
const mobileCategoryHeight =
|
||||||
activeCategoryRows * 88 + Math.max(0, activeCategoryRows - 1) * 8;
|
maxCategoryRows * 88 + Math.max(0, maxCategoryRows - 1) * 8;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const row = categoryRowRef.current;
|
const row = categoryRowRef.current;
|
||||||
|
|||||||
Reference in New Issue
Block a user