Blogs

Reading material to get you started on your FinOps and cloud cost optimization journey

Reading material to get you started on your FinOps and cloud cost optimization journey

MORE BLOGS
MORE BLOGS

Can your engineering context keep up with the speed of AI?

Start with a 14-day audit of your engineering systems. Read-only. No commitment.

STAY AHEAD

Can your engineering context keep up with the speed of AI?

Start with a 14-day audit of your engineering systems. Read-only. No commitment.

STAY AHEAD

Can your engineering context keep up with the speed of AI?

Start with a 14-day audit of your engineering systems. Read-only. No commitment.

STAY AHEAD

import { useEffect } from "react" import { addPropertyControls, ControlType } from "framer" // Drop on the Blog CMS page template. Bind props to CMS fields. // Outputs Article + BreadcrumbList + FAQPage JSON-LD on /blogs/{slug} only. interface P { title: string description: string slug: string datePublished: string dateModified: string authorName: string imageUrl: string logoUrl: string siteUrl: string articleSelector: string } function toISO(v: string) { if (!v) return undefined const x = v.match(/^(\d{2})\/(\d{2})\/(\d{4})$/) if (x) return `${x[3]}-${x[2]}-${x[1]}` const d = new Date(v) return isNaN(d.getTime()) ? v : d.toISOString().split("T")[0] } function parseFaq(sel: string) { const root = (sel && document.querySelector(sel)) || document.body if (!root) return [] const h = Array.from(root.querySelectorAll("h2")).find((e) => /frequently asked questions|faq/i.test(e.textContent || "") ) if (!h) return [] const out: { q: string; a: string }[] = [] let c: { q: string; a: string } | null = null let n = h.nextElementSibling while (n && n.tagName !== "H2") { if (n.tagName === "H3" || n.tagName === "H4") { if (c && c.a) out.push(c) c = { q: (n.textContent || "").trim(), a: "" } } else if (c && (n.textContent || "").trim()) { c.a += (c.a ? " " : "") + (n.textContent || "").trim() } n = n.nextElementSibling } if (c && c.a) out.push(c) return out } export default function BlogSchema(p: P) { useEffect(() => { if (typeof document === "undefined" || !p.slug) return const path = window.location.pathname.replace(/\/+$/, "") if (!/^\/blogs\/[^/]+$/.test(path)) return const base = p.siteUrl.replace(/\/+$/, "") const url = `${base}/blogs/${p.slug}` const g: any[] = [ { "@type": "BlogPosting", "@id": `${url}/#article`, headline: p.title, description: p.description || undefined, image: p.imageUrl ? [p.imageUrl] : undefined, datePublished: toISO(p.datePublished), dateModified: toISO(p.dateModified || p.datePublished), author: { "@type": "Organization", name: p.authorName || "Amnic", url: base, }, publisher: { "@type": "Organization", name: "Amnic", logo: p.logoUrl ? { "@type": "ImageObject", url: p.logoUrl } : undefined, }, mainEntityOfPage: { "@type": "WebPage", "@id": url }, }, { "@type": "BreadcrumbList", "@id": `${url}/#breadcrumb`, itemListElement: [ { "@type": "ListItem", position: 1, name: "Home", item: base }, { "@type": "ListItem", position: 2, name: "Blogs", item: `${base}/blogs` }, { "@type": "ListItem", position: 3, name: p.title, item: url }, ], }, ] const f = parseFaq(p.articleSelector) if (f.length) g.push({ "@type": "FAQPage", "@id": `${url}/#faq`, mainEntity: f.map((q) => ({ "@type": "Question", name: q.q, acceptedAnswer: { "@type": "Answer", text: q.a }, })), }) const id = "blog-schema-jsonld" document.getElementById(id)?.remove() const el = document.createElement("script") el.type = "application/ld+json" el.id = id el.text = JSON.stringify( { "@context": "https://schema.org", "@graph": g }, (_k, v) => (v === undefined ? undefined : v) ) document.head.appendChild(el) return () => document.getElementById(id)?.remove() }, [p]) return null } BlogSchema.displayName = "Blog Schema (JSON-LD)" const S = (title: string, defaultValue?: string) => ({ type: ControlType.String, title, ...(defaultValue ? { defaultValue } : {}), }) addPropertyControls(BlogSchema, { title: S("Title"), description: S("Description"), slug: S("Slug"), datePublished: S("Date Published"), dateModified: S("Date Modified"), authorName: S("Author", "Amnic"), imageUrl: S("Image URL"), logoUrl: S("Logo URL", "https://amnic.com/logo.png"), siteUrl: S("Site URL", "https://amnic.com"), articleSelector: S("Article Selector"), })