homepage: typography upgrade + ArticleFeed polish

- layout.tsx: load Lora (serif) + Inter (sans) via next/font/google,
  self-hosted at build time, exposed as --font-serif / --font-sans
  CSS variables on <html>. No CDN fetch, no FOIT, no GDPR concern.
- tailwind.css: --font-heading and --font-body now reference the
  next/font variables with Georgia / -apple-system fallbacks for the
  brief window before the self-hosted face is ready. --font-mono
  upgraded to IBM Plex Mono → ui-monospace → Courier New fallback
  (DoubleTicker chips already specify IBM Plex Mono directly).
- ArticleFeed: drop the FEATURED filter chip (duplicates the
  Staff Editorial section above), add publish date alongside the
  byline on every card, lift the homepage feed cap from 200 → 5000.
- api/public/posts: lift MAX_LIMIT to 10000 so client-side
  pagination + infinite-scroll see the full archive.
This commit is contained in:
Ryan Salazar
2026-05-21 01:51:29 +00:00
parent 567a45079f
commit 78c2ee656e
4 changed files with 42 additions and 9 deletions

View File

@@ -3,7 +3,10 @@ import { getLatestImportedArticles } from "@/lib/articles/legacy-source";
export const revalidate = 300;
const MAX_LIMIT = 200;
// Homepage feed now renders every imported post; pagination + infinite-
// scroll happen client-side over the full set. Keep an absolute ceiling
// only as a safety valve, not a UX cap.
const MAX_LIMIT = 10000;
const DEFAULT_LIMIT = 100;
export async function GET(request: Request) {

View File

@@ -26,7 +26,7 @@ interface ArticleItem {
const ALL_CATEGORIES = ["All", "BROADCAST", "FEATURED", "POST PRODUCTION", "ANIMATION"];
const ALL_CATEGORIES = ["All", "BROADCAST", "POST PRODUCTION", "ANIMATION"];
const SOURCE_FILTERS = ["All", "Live", "Imported"] as const;
type SourceFilter = typeof SOURCE_FILTERS[number];
type FeedMode = "pagination" | "infinite";
@@ -94,7 +94,7 @@ export default function ArticleFeed() {
let cancelled = false;
(async () => {
try {
const res = await fetch("/api/public/posts?limit=200", { cache: "no-store" });
const res = await fetch("/api/public/posts?limit=5000", { cache: "no-store" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
const items = Array.isArray(json?.items) ? (json.items as ArticleItem[]) : [];
@@ -613,11 +613,19 @@ export default function ArticleFeed() {
{article?.excerpt}
</p>
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-1 hidden sm:flex">
<div className="hidden sm:flex items-center gap-2 text-xs text-[#666] min-w-0">
<PersonIcon size={11} className="text-[#666] flex-shrink-0" />
<span className="font-body text-xs text-[#666]">
<span className="font-body truncate">
By {article?.author}
</span>
{article?.date && (
<>
<span aria-hidden="true" className="text-[#333]">·</span>
<time className="font-body whitespace-nowrap" dateTime={article.date}>
{article.date}
</time>
</>
)}
</div>
<Link
href={articleHref}

View File

@@ -1,6 +1,25 @@
import React, { Suspense } from 'react';
import type { Metadata, Viewport } from 'next';
import { Lora, Inter } from 'next/font/google';
import '../styles/tailwind.css';
// Self-hosted at build time by next/font — no runtime CDN fetch, no FOIT,
// no GDPR concern. The two variables are consumed by --font-heading and
// --font-body in src/styles/tailwind.css with Georgia/Arial fallbacks.
const lora = Lora({
subsets: ['latin'],
weight: ['400', '500', '600', '700'],
style: ['normal', 'italic'],
variable: '--font-serif',
display: 'swap',
});
const inter = Inter({
subsets: ['latin'],
weight: ['300', '400', '500', '600', '700', '800'],
variable: '--font-sans',
display: 'swap',
});
// SystemStatusBar removed — the "articles indexed / events tracked / [v2.0.0]"
// strip was eating vertical space without serving readers.
import AskBBAI from '@/components/AskBBAI';
@@ -81,7 +100,7 @@ export default function RootLayout({
}: Readonly<{children: React.ReactNode;}>) {
return (
<html lang="en">
<html lang="en" className={`${lora.variable} ${inter.variable}`}>
<head>
{/* hreflang entries removed pending real i18n routes (Phase D). */}

View File

@@ -17,9 +17,12 @@
--color-border: #2a2a2a;
--color-top-bar: #1a2535;
--color-sub-nav: #161c28;
--font-heading: Georgia, 'Times New Roman', serif;
--font-body: Arial, Helvetica, sans-serif;
--font-mono: 'Courier New', Courier, monospace;
/* --font-serif and --font-sans are injected on <html> by next/font/google
(Lora + Inter) in src/app/layout.tsx. The system-font tails are real
fallbacks for the brief window before the self-hosted face is ready. */
--font-heading: var(--font-serif), Georgia, 'Times New Roman', serif;
--font-body: var(--font-sans), -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
--font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, 'Courier New', monospace;
--transition-fast: 0.18s ease;
--transition-base: 0.25s ease;
--transition-slow: 0.4s ease;