diff --git a/src/api/templates.js b/src/api/templates.js new file mode 100644 index 0000000..0ab5236 --- /dev/null +++ b/src/api/templates.js @@ -0,0 +1,31 @@ +const API_BASE = "/api"; + +const cache = new Map(); // key -> Promise + +export async function fetchDefaultTemplate(typeKey = "news") { + const t = (typeKey || "news").toLowerCase().trim(); + const res = await fetch(`${API_BASE}/templates/default?type=${encodeURIComponent(t)}`, { + credentials: "include", + }); + if (!res.ok) { + const text = await res.text().catch(() => ""); + throw new Error(`fetchDefaultTemplate failed: ${res.status} ${text}`); + } + return res.json(); +} + +// One-per-type cached fetch +export function getDefaultTemplateCached(typeKey = "news") { + const t = (typeKey || "news").toLowerCase().trim(); + if (cache.has(t)) return cache.get(t); + + const p = fetchDefaultTemplate(t) + .then((tpl) => tpl) + .catch((err) => { + cache.delete(t); + throw err; + }); + + cache.set(t, p); + return p; +} diff --git a/src/components/Map/TemplateMarkerCard.jsx b/src/components/Map/TemplateMarkerCard.jsx new file mode 100644 index 0000000..c708464 --- /dev/null +++ b/src/components/Map/TemplateMarkerCard.jsx @@ -0,0 +1,65 @@ +import React, { useMemo } from "react"; +import CardRenderer from "../Cards/CardRenderer"; +import { cardTokens } from "../../theme/cardTokens"; + +function normTheme(t) { + if (t === "dark" || t === "blue" || t === "light") return t; + return "dark"; +} + +export default function TemplateMarkerCard({ + post, + template, + theme = "dark", + mode = "full", // "mini" or "full" + onOpenUrl, +}) { + const spec = mode === "mini" ? template?.mini_spec_json : template?.full_spec_json; + + const data = useMemo(() => { + return { + headline: post?.title || "Untitled", + source: post?.source || (post?.author ? `by ${post.author}` : "") || (post?.sub_category || ""), + summary: post?.snippet || post?.body || post?.content || "", + url: post?.url || "", + image: post?.image_large || post?.image_small || post?.image || post?.media_url || "", + }; + }, [post]); + + if (!spec) { + // fallback simple + return ( +