delete sampleArticles seed; serve all sections from bb.wp_imported_posts (DB)
Eliminates 72 hardcoded rocket.new image refs in one shot. Section pages (/gear, /technology, /show-coverage, /news) now render from bb.wp_imported_posts via getLegacyArticlesBySection(section), which maps each non-news section to a curated tag set (e.g. gear -> Audio, Cameras, lighting, Blackmagic Design, monitoring; technology -> AI, Streaming, OTT, IP, Cloud, AV; show-coverage -> NAB, IBC, BroadcastAsia). Also: - src/lib/articles/types.ts: Article interface lifted out of the deleted seed file. Type-only consumers (NewsArticleDetailClient, ArticleDetailClient, legacy-source) re-imported from here. - /news (client component) now wrapped: server fetches articles from DB and passes to NewsPageClient. Filter UI unchanged. - generateStaticParams on /news/[slug] and /articles/[slug] no longer references seed slugs; pre-renders 50 most-recent imported slugs and relies on dynamicParams + revalidate=3600 for the rest. - sitemap.ts now sources article URLs from getLegacyRecentSitemapEntries() (up to 5000 most-recent imported posts). Default BASE_URL fallback updated from the rocket.new placeholder to bb-staging.onsethost.com. - src/app/api/ai/article-suggestions/route.ts now pulls candidates from the DB (top 100 recent news) and resolves AI-returned slugs via DB lookup if not in the candidate window. Inline rocket.new image refs in homepage components (ArticleFeed, FeaturedBento) are unchanged in this commit; those are inline seed arrays in the components, not imports of sampleArticles.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import type { Article } from "./sampleArticles";
|
||||
import type { Article } from "./types";
|
||||
import { rewriteLegacyImageUrl, rewriteLegacyImageUrlsInHtml } from "@/lib/legacy-image";
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
@@ -30,24 +30,46 @@ interface ImportedPostRow {
|
||||
|
||||
const FALLBACK_IMAGE = "/legacy/site/no_image.png";
|
||||
|
||||
// Tag → section mapping. Source: tag distribution observed in
|
||||
// bb.wp_imported_posts. Matches against any overlap (lowercased).
|
||||
type Section = Article["section"];
|
||||
const SECTION_TAGS: Record<Section, string[]> = {
|
||||
gear: [
|
||||
"Audio", "Cameras", "lighting", "Lighting", "Reviews",
|
||||
"Blackmagic Design", "blackmagic", "Sony", "Canon", "ARRI", "RED",
|
||||
"monitoring", "Test and Measurement",
|
||||
],
|
||||
technology: [
|
||||
"AI", "Streaming", "OTT", "ip", "IP", "Cloud",
|
||||
"AV", "audio-over-IP interfaces",
|
||||
"IP Workflows", "Live Production", "Cloud Production",
|
||||
"MAM", "Storage", "Encoding",
|
||||
],
|
||||
"show-coverage": [
|
||||
"NAB", "NAB Show", "NAB 2025", "NAB 2026",
|
||||
"IBC", "IBC 2025", "IBC 2026",
|
||||
"BroadcastAsia", "BroadcastAsia 2026", "Broadcast Asia 2026",
|
||||
"InfoComm", "MPTS",
|
||||
],
|
||||
news: [], // catch-all — no tag filter
|
||||
};
|
||||
|
||||
function authorSlug(name: string | null): string {
|
||||
if (!name) return "staff-reporter";
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.slice(0, 60) || "staff-reporter";
|
||||
return (
|
||||
name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.slice(0, 60) || "staff-reporter"
|
||||
);
|
||||
}
|
||||
|
||||
function formatDate(iso: string | null): string {
|
||||
if (!iso) return "";
|
||||
const d = new Date(iso);
|
||||
if (isNaN(d.getTime())) return "";
|
||||
return d.toLocaleDateString("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
|
||||
}
|
||||
|
||||
function readTime(content: string | null): string {
|
||||
@@ -58,7 +80,7 @@ function readTime(content: string | null): string {
|
||||
return `${minutes} min read`;
|
||||
}
|
||||
|
||||
function rowToArticle(row: ImportedPostRow): Article {
|
||||
function rowToArticle(row: ImportedPostRow, section: Section = "news"): Article {
|
||||
const image = row.featured_image
|
||||
? rewriteLegacyImageUrl(row.featured_image)
|
||||
: FALLBACK_IMAGE;
|
||||
@@ -66,7 +88,7 @@ function rowToArticle(row: ImportedPostRow): Article {
|
||||
const author = row.author_name || "Staff Reporter";
|
||||
return {
|
||||
slug: row.wp_slug,
|
||||
section: "news",
|
||||
section,
|
||||
title: row.title,
|
||||
excerpt: row.excerpt || "",
|
||||
category: (row.category || "NEWS").toUpperCase(),
|
||||
@@ -83,13 +105,14 @@ function rowToArticle(row: ImportedPostRow): Article {
|
||||
};
|
||||
}
|
||||
|
||||
const SELECT_COLS =
|
||||
"wp_id,wp_slug,title,excerpt,content,author_name,category,tags,featured_image,featured_image_alt,status,wp_published_at";
|
||||
|
||||
export async function getLegacyArticleBySlug(slug: string): Promise<Article | null> {
|
||||
try {
|
||||
const { data, error } = await client()
|
||||
.from("wp_imported_posts")
|
||||
.select(
|
||||
"wp_id,wp_slug,title,excerpt,content,author_name,category,tags,featured_image,featured_image_alt,status,wp_published_at",
|
||||
)
|
||||
.select(SELECT_COLS)
|
||||
.eq("wp_slug", slug)
|
||||
.eq("status", "published")
|
||||
.maybeSingle();
|
||||
@@ -108,9 +131,7 @@ export async function getLegacyRelatedArticles(
|
||||
try {
|
||||
let q = client()
|
||||
.from("wp_imported_posts")
|
||||
.select(
|
||||
"wp_id,wp_slug,title,excerpt,content,author_name,category,tags,featured_image,featured_image_alt,status,wp_published_at",
|
||||
)
|
||||
.select(SELECT_COLS)
|
||||
.eq("status", "published")
|
||||
.neq("wp_slug", excludeSlug)
|
||||
.order("wp_published_at", { ascending: false })
|
||||
@@ -118,7 +139,32 @@ export async function getLegacyRelatedArticles(
|
||||
if (category) q = q.eq("category", category);
|
||||
const { data, error } = await q;
|
||||
if (error || !data) return [];
|
||||
return (data as ImportedPostRow[]).map(rowToArticle);
|
||||
return (data as ImportedPostRow[]).map((r) => rowToArticle(r));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** Section-filtered listing. `news` returns all; gear/technology/show-coverage
|
||||
* filter by tag overlap against SECTION_TAGS. */
|
||||
export async function getLegacyArticlesBySection(
|
||||
section: Section,
|
||||
limit = 200,
|
||||
): Promise<Article[]> {
|
||||
try {
|
||||
let q = client()
|
||||
.from("wp_imported_posts")
|
||||
.select(SELECT_COLS)
|
||||
.eq("status", "published")
|
||||
.order("wp_published_at", { ascending: false })
|
||||
.limit(limit);
|
||||
const tags = SECTION_TAGS[section];
|
||||
if (tags.length > 0) {
|
||||
q = q.overlaps("tags", tags);
|
||||
}
|
||||
const { data, error } = await q;
|
||||
if (error || !data) return [];
|
||||
return (data as ImportedPostRow[]).map((r) => rowToArticle(r, section));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
@@ -137,3 +183,22 @@ export async function getLegacyRecentSlugs(limit = 200): Promise<string[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getLegacyRecentSitemapEntries(
|
||||
limit = 5000,
|
||||
): Promise<{ slug: string; date: string }[]> {
|
||||
try {
|
||||
const { data } = await client()
|
||||
.from("wp_imported_posts")
|
||||
.select("wp_slug,wp_published_at")
|
||||
.eq("status", "published")
|
||||
.order("wp_published_at", { ascending: false })
|
||||
.limit(limit);
|
||||
return (data || []).map((r: { wp_slug: string; wp_published_at: string | null }) => ({
|
||||
slug: r.wp_slug,
|
||||
date: r.wp_published_at || new Date().toISOString(),
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user