// src/components/news/NewsCard.tsx "use client"; import Image from "next/image"; import Link from "next/link"; import dayjs from "dayjs"; import { useMemo } from "react"; import type { NewsItem } from "@/types/news"; const stripTags = (html?: string | null) => (html ? html.replace(/<[^>]+>/g, "") : ""); // HTMLエンティティをデコード const decodeEntities = (text: string) => { const textarea = document.createElement("textarea"); textarea.innerHTML = text; return textarea.value; }; export default function NewsCard({ item }: { item: NewsItem }) { const summary = useMemo(() => { if (!item.content) return ""; const plain = decodeEntities(stripTags(item.content)); return plain.length > 80 ? plain.slice(0, 80) + "…" : plain; }, [item.content]); const href = (() => { const url = item.linkurl?.trim(); // リンクなし(none/空)の場合は詳細ページへ if (!url || url.toLowerCase() === "none") { return `/news/${item.id}`; } // 外部URLはそのまま if (/^https?:\/\//i.test(url)) { return url; } // 内部スラッグ(相対指定)の場合 return `/news/${url}`; })(); const target = item.link_target === "_blank" ? "_blank" : "_self"; const isExternal = href?.startsWith("http"); const imageId = typeof item.thumbnail === "string" ? item.thumbnail : item.thumbnail?.id; const imageSrc = imageId ? `${process.env.NEXT_PUBLIC_DIRECTUS_ASSETS_URL}/assets/${imageId}?fit=cover` : "/dummy_thumb.png"; const date = dayjs(item.published_at).format("YYYY.MM.DD"); const cardInner = (
{stripTags(item.title)

{date}

{stripTags(item.title)}

{summary &&

{summary}

}
{Array.isArray(item.tags) && item.tags.length > 0 && (
{item.tags.map((tag, i) => ( #{tag} ))}
)}
); if (!href) return cardInner; if (isExternal) return ( {cardInner} ); return ( {cardInner} ); }