import { useMemo, useState } from "react"; import { Link } from "react-router-dom"; import { mediaUrl } from "../api"; import { mainTopics, topicKey } from "../topics"; import useJournalResource from "../useJournalResource"; import Icon from "../components/Icon"; import PageHeader from "../components/PageHeader"; import ArticleAdminActions from "../components/ArticleAdminActions"; import { useAdmin } from "../components/AdminSession"; import { ErrorState, LoadingState } from "../components/Status"; function formatDate(date) { return new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", year: "numeric", }).format(new Date(`${date}T12:00:00`)); } function PostCard({ post, featured, onDeleted }) { return (
{formatDate(post.published_at)} {post.read_time} min read

{post.title}

{post.excerpt}

{post.tags.slice(0, 2).map((tag) => {tag})}
); } export default function BlogPage() { const { isAdmin } = useAdmin(); const { data, setData: setPosts, loading, error, reload } = useJournalResource(); const posts = data ?? []; const [query, setQuery] = useState(""); const [activeTag, setActiveTag] = useState(null); const [showOthers, setShowOthers] = useState(false); const tags = [null, ...mainTopics]; const customTopics = useMemo(() => { const mainKeys = new Set(mainTopics.map(topicKey)); const custom = new Map(); posts.flatMap((post) => post.tags).forEach((tag) => { const key = topicKey(tag); if (key && !mainKeys.has(key) && !custom.has(key)) custom.set(key, tag.trim()); }); return [...custom.values()].sort((a, b) => a.localeCompare(b)); }, [posts]); const customActive = activeTag !== null && !mainTopics.some((tag) => topicKey(tag) === topicKey(activeTag)); const filteredPosts = useMemo(() => { const needle = query.trim().toLowerCase(); return posts.filter((post) => { const matchesTag = activeTag === null || post.tags.some((tag) => topicKey(tag) === topicKey(activeTag)); const matchesQuery = !needle || `${post.title} ${post.excerpt} ${post.tags.join(" ")}`.toLowerCase().includes(needle); return matchesTag && matchesQuery; }); }, [activeTag, posts, query]); return (

{posts.length}field notes

{isAdmin && New article} )} />
{tags.map((tag) => ( ))}
{loading && !data && } {error && } {loading && data &&

Refreshing articles...

} {filteredPosts.length > 0 && (
{filteredPosts.map((post, index) => ( setPosts((current) => current.filter((item) => item.slug !== slug))} /> ))}
)} {!loading && !error && filteredPosts.length === 0 && (

No notes found

Try a different phrase or topic.

)}
); }