"use client"; import { Container } from "@/components/container"; import { format } from "date-fns"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; import FuzzySearch from "fuzzy-search"; import type { BlogEntry } from "./page"; function truncate(text: string, length: number) { return text.length > length ? `${text.slice(0, length)}…` : text; } function SearchIcon({ className }: { className?: string }) { return ( ); } export function BlogWithSearchMagazine({ blogs }: { blogs: BlogEntry[] }) { const featured = blogs[0]; if (!featured) { return (

No blog posts yet.

); } return (

Blog

); } function MagazineFeatured({ blog }: { blog: BlogEntry }) { return (
{blog.image ? ( {blog.title} ) : null}
Cover story

{blog.title}

{truncate(blog.description, 160)}

{blog.author} {blog.author} ·
); } function MagazineSearchGrid({ blogs: allBlogs, featuredSlug, }: { blogs: BlogEntry[]; featuredSlug: string; }) { const [search, setSearch] = useState(""); const searcher = useMemo( () => new FuzzySearch(allBlogs, ["title", "description"], { caseSensitive: false, }), [allBlogs], ); const [results, setResults] = useState(allBlogs); useEffect(() => { setResults(searcher.search(search)); }, [search, searcher]); const gridItems = useMemo(() => { if (search.trim()) { return results; } return results.filter((b) => b.slug !== featuredSlug); }, [results, search, featuredSlug]); return (

From the archive

{gridItems.length === 0 ? (

No articles match that search.

) : (
    {gridItems.map((blog) => (
  • ))}
)}
); } function MagazineCard({ blog }: { blog: BlogEntry }) { return (
{blog.image ? ( {blog.title} ) : (
No image
)}

{blog.title}

{truncate(blog.description, 110)}

{blog.author} {blog.author}
); }