From dbac6fbdb8a86098059360e8cfbd2654601263e6 Mon Sep 17 00:00:00 2001 From: ZJ van de Weg Date: Wed, 30 Sep 2026 20:10:01 -0700 Subject: [PATCH 1/2] Render every use case from one template and share repeated bands All eight /use-cases/ pages now render through pages/use-cases/[slug].vue from content/use-cases/.yml. Each entry is listing metadata plus an ordered `sections` list; a section's `type` selects a component in components/use-case/. The six hand-written pages (scada, mes, uns, data-integration, it-ot-middleware, remote-device-management) are removed and their copy moved into YAML unchanged, apart from one typo fix. Copy in YAML goes through lib/rich-text.mjs: links, bold, ==indigo== and !!red!! accents, escaped first so content cannot inject raw HTML. Bands that were duplicated across the site are now shared components: - ClosingCta replaces IndustryPageCta, IndustryCta and the use-case CTA, keeping each caller's PostHog position. - FaqSection renders the heading, accordion and FAQPage structured data, replacing hand-written copies on nine pages; BlogFaq loses its `page` variant, which only existed for that pairing. - StepList replaces the copies on opcua, device-agent and remote-device-management. - ResourceList replaces the thumbnail card markup on plc, opcua and the use-case resources band. --- nuxt/components/ActionButtons.vue | 43 +++ nuxt/components/BlogFaq.vue | 21 +- nuxt/components/ClosingCta.vue | 49 +++ nuxt/components/FaqSection.vue | 42 +++ nuxt/components/ResourceList.vue | 35 ++ nuxt/components/StepList.vue | 61 ++++ nuxt/components/industry-page/Cta.vue | 18 - nuxt/components/industry-page/Template.vue | 19 +- nuxt/components/industry/Cta.vue | 17 - nuxt/components/use-case/AiBuildLayer.vue | 4 +- nuxt/components/use-case/ClosingCta.vue | 29 -- nuxt/components/use-case/Comparison.vue | 4 +- nuxt/components/use-case/Competition.vue | 4 +- .../components/use-case/DeploymentOptions.vue | 55 +++ nuxt/components/use-case/Features.vue | 125 +++++++ nuxt/components/use-case/Hero.vue | 102 +++++- nuxt/components/use-case/Outcomes.vue | 4 +- nuxt/components/use-case/Pain.vue | 4 +- nuxt/components/use-case/Prose.vue | 45 +++ nuxt/components/use-case/Resources.vue | 32 ++ nuxt/components/use-case/Results.vue | 71 ++++ nuxt/components/use-case/SolutionHero.vue | 31 -- nuxt/components/use-case/WhyItMatters.vue | 4 +- nuxt/content.config.ts | 264 +++++++++++--- nuxt/content/use-cases/data-integration.yml | 60 +++- nuxt/content/use-cases/it-ot-middleware.yml | 74 +++- nuxt/content/use-cases/mes.yml | 57 +++- .../use-cases/production-monitoring.yml | 221 ++++++------ .../use-cases/remote-device-management.yml | 131 ++++++- nuxt/content/use-cases/scada.yml | 51 ++- .../use-cases/shop-floor-communication.yml | 177 +++++----- nuxt/content/use-cases/uns.yml | 65 +++- nuxt/lib/rich-text.mjs | 30 ++ nuxt/lib/rich-text.test.mjs | 47 +++ nuxt/pages/ai/index.vue | 18 +- nuxt/pages/index.vue | 16 +- nuxt/pages/industries/[slug].vue | 7 +- nuxt/pages/integrations/opcua.vue | 89 ++--- nuxt/pages/landing/plc.vue | 44 +-- nuxt/pages/node-red/index.vue | 14 +- nuxt/pages/platform/device-agent.vue | 64 +--- nuxt/pages/platform/why-flowfuse.vue | 11 +- nuxt/pages/resources/roi-calculator.vue | 11 +- nuxt/pages/use-cases/[slug].vue | 119 ++++--- nuxt/pages/use-cases/data-integration.vue | 145 -------- nuxt/pages/use-cases/index.vue | 6 +- nuxt/pages/use-cases/it-ot-middleware.vue | 240 ------------- nuxt/pages/use-cases/mes.vue | 149 -------- .../use-cases/remote-device-management.vue | 322 ------------------ nuxt/pages/use-cases/scada.vue | 132 ------- nuxt/pages/use-cases/uns.vue | 181 ---------- 51 files changed, 1725 insertions(+), 1839 deletions(-) create mode 100644 nuxt/components/ActionButtons.vue create mode 100644 nuxt/components/ClosingCta.vue create mode 100644 nuxt/components/FaqSection.vue create mode 100644 nuxt/components/ResourceList.vue create mode 100644 nuxt/components/StepList.vue delete mode 100644 nuxt/components/industry-page/Cta.vue delete mode 100644 nuxt/components/industry/Cta.vue delete mode 100644 nuxt/components/use-case/ClosingCta.vue create mode 100644 nuxt/components/use-case/DeploymentOptions.vue create mode 100644 nuxt/components/use-case/Features.vue create mode 100644 nuxt/components/use-case/Prose.vue create mode 100644 nuxt/components/use-case/Resources.vue create mode 100644 nuxt/components/use-case/Results.vue delete mode 100644 nuxt/components/use-case/SolutionHero.vue create mode 100644 nuxt/lib/rich-text.mjs create mode 100644 nuxt/lib/rich-text.test.mjs delete mode 100644 nuxt/pages/use-cases/data-integration.vue delete mode 100644 nuxt/pages/use-cases/it-ot-middleware.vue delete mode 100644 nuxt/pages/use-cases/mes.vue delete mode 100644 nuxt/pages/use-cases/remote-device-management.vue delete mode 100644 nuxt/pages/use-cases/scada.vue delete mode 100644 nuxt/pages/use-cases/uns.vue diff --git a/nuxt/components/ActionButtons.vue b/nuxt/components/ActionButtons.vue new file mode 100644 index 0000000000..0c44c4e2e7 --- /dev/null +++ b/nuxt/components/ActionButtons.vue @@ -0,0 +1,43 @@ + + + diff --git a/nuxt/components/BlogFaq.vue b/nuxt/components/BlogFaq.vue index 1011af4c5d..d12b330e4d 100644 --- a/nuxt/components/BlogFaq.vue +++ b/nuxt/components/BlogFaq.vue @@ -4,20 +4,11 @@ // paragraphs, which the 11ty pages expressed with raw and

tags under `| safe`. import { isListBlock, renderFaqAnswer } from '../lib/faq-answer.mjs' -withDefaults(defineProps<{ +// Inside an article it sits under the post's own heading; on a marketing page +// supplies the heading, the band and the FAQPage structured data. +defineProps<{ faq: Array<{ question: string, answer: string }> - /** - * How much room the block takes above the first question. - * - * faq.njk had exactly these two modes: `post` inside an article, `page` everywhere a - * marketing page pairs it with its own

. Those pages set a negative bottom margin - * on that heading, which only reads correctly against the taller spacing, so a page - * rendering this in post mode pulls its first question up over its own heading. - */ - variant?: 'post' | 'page' -}>(), { - variant: 'post', -}) +}>() const openIndex = ref(null) function toggle(i: number) { @@ -26,8 +17,8 @@ function toggle(i: number) {