Files
QR-master/src/lib/content.ts

80 lines
2.9 KiB
TypeScript

import { blogPosts } from "./blog-data";
import { authors } from "./author-data";
import type { BlogPost, PillarKey, AuthorProfile } from "./types";
/**
* Blog slugs that are 301-redirected in next.config.mjs.
* They must not appear in the blog index, the learn pillars, the sitemap
* or IndexNow submissions - linking to a redirect source wastes crawl budget
* and passes link equity through an unnecessary hop.
* Keep this in sync with the redirects() block in next.config.mjs.
*/
export const REDIRECTED_BLOG_SLUGS = new Set<string>([
"qr-code-analytics",
"qr-code-restaurant-menu",
// Duplicate of the standalone /qr-code-print-size-guide, which is the version
// Google actually ranks. Both were live and self-canonical until 2026-08-13.
"qr-code-print-size-guide",
]);
export function isRedirectedSlug(slug: string): boolean {
return REDIRECTED_BLOG_SLUGS.has(slug);
}
export function getPublishedPosts(): BlogPost[] {
const currentDate = new Date();
return blogPosts.filter(p => {
if (!p.published) return false;
if (REDIRECTED_BLOG_SLUGS.has(p.slug)) return false;
const publishDate = p.datePublished ? new Date(p.datePublished) : new Date(p.date);
return publishDate <= currentDate;
});
}
export function getPostBySlug(slug: string): BlogPost | undefined {
return blogPosts.find(p => p.slug === slug);
}
export function getPublishedPostBySlug(slug: string): BlogPost | undefined {
const p = getPostBySlug(slug);
if (!p?.published) return undefined;
const currentDate = new Date();
const publishDate = p.datePublished ? new Date(p.datePublished) : new Date(p.date);
return publishDate <= currentDate ? p : undefined;
}
export function getPostsByPillar(pillar: PillarKey): BlogPost[] {
return getPublishedPosts()
.filter(p => p.pillar === pillar)
.sort((a, b) => (new Date(a.datePublished).getTime() < new Date(b.datePublished).getTime() ? 1 : -1));
}
export function getAuthorBySlug(slug: string): AuthorProfile | undefined {
return authors.find(a => a.slug === slug);
}
export function getPostsByAuthor(slug: string): BlogPost[] {
return getPublishedPosts()
.filter(p => p.authorSlug === slug)
.sort((a, b) => (new Date(a.datePublished).getTime() < new Date(b.datePublished).getTime() ? 1 : -1));
}
export function getRelatedPosts(post: BlogPost, limit = 4): BlogPost[] {
const published = getPublishedPosts();
// explicit relatedSlugs first
const explicit = (post.relatedSlugs ?? [])
.map(s => published.find(p => p.slug === s))
.filter((p): p is BlogPost => !!p);
if (explicit.length >= limit) return explicit.slice(0, limit);
// fallback: same pillar, not itself, newest
const fallback = published
.filter(p => p.slug !== post.slug && p.pillar === post.pillar)
.slice(0, limit - explicit.length);
return [...explicit, ...fallback];
}