diff --git a/.eleventy.js b/.eleventy.js index 4f889682c9..bcd1ffc878 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -107,7 +107,7 @@ module.exports = function(eleventyConfig) { }); // Add a global data variable for the current date - eleventyConfig.addGlobalData("currentDateISO", new Date().toISOString()); + eleventyConfig.addGlobalData("currentDateISO", new Date().toISOString()); // Make filters globally accessible global.isFuturePost = eleventyConfig.getFilter('isFuturePost'); @@ -226,6 +226,13 @@ module.exports = function(eleventyConfig) { eleventyConfig.addFilter("limit", (arr, limit) => arr.slice(0, limit )); + // Marketing image for a nav highlight card: the linked page's image front matter + eleventyConfig.addFilter("pageImageForUrl", (collection, url) => { + const normalized = url && !url.endsWith("/") ? `${url}/` : url; + const match = (collection || []).find((p) => p.url === normalized); + return (match && match.data && match.data.image) || null; + }); + eleventyConfig.addFilter('console', function (value) { const str = util.inspect(value, { showHidden: false, depth: null }); return `
${unescape(str)}
;` @@ -963,11 +970,11 @@ module.exports = function(eleventyConfig) { if (content) { const chevronDown = loadSVG('chevron-down') - return `
  • ${iconSvg}${label}${chevronDown}${content}
  • ` + return `
  • ${iconSvg}${label}${chevronDown}${content}
  • ` } else if (link) { - return `
  • ${iconSvg}${label}
  • ` + return `
  • ${iconSvg}${label}
  • ` } else { - return `
  • ${iconSvg}${label}
  • ` + return `
  • ${iconSvg}${label}
  • ` } }); diff --git a/nuxt/components/AppFooter.vue b/nuxt/components/AppFooter.vue index 5ea34b2370..6165e17966 100644 --- a/nuxt/components/AppFooter.vue +++ b/nuxt/components/AppFooter.vue @@ -1,11 +1,128 @@ diff --git a/nuxt/components/AppHeader.vue b/nuxt/components/AppHeader.vue index 890543e9df..e642e87b33 100644 --- a/nuxt/components/AppHeader.vue +++ b/nuxt/components/AppHeader.vue @@ -1,5 +1,11 @@ + + diff --git a/nuxt/layouts/default.vue b/nuxt/layouts/default.vue index 328839dea7..43602ed01d 100644 --- a/nuxt/layouts/default.vue +++ b/nuxt/layouts/default.vue @@ -3,6 +3,7 @@ Skip to main content
    +
    diff --git a/src/_data/navHighlights.json b/src/_data/navHighlights.json new file mode 100644 index 0000000000..7e64a99026 --- /dev/null +++ b/src/_data/navHighlights.json @@ -0,0 +1,23 @@ +{ + "_comment": "Nav highlight cards, one per top-nav dropdown. Marketing owns this file: each entry is the promo card shown at the left of the corresponding mega dropdown on xl+ screens. Swap an entry to feature a campaign, webinar, customer story or launch. Each card renders as the image plus the title (which also serves as the link's accessible name); keep titles short (2 lines max). Set image to a site-absolute path to override, otherwise the card uses the linked page's front-matter image, falling back to /images/og-blog.jpg. Consumed by Eleventy (base.njk) and by Nuxt (nuxt/components/AppHeader.vue).", + "platform": { + "title": "Industrial AI, governed and built in", + "link": "/ai/", + "image": "/images/ai/ai-hero.png" + }, + "solutions": { + "title": "Scale automotive operations", + "link": "/industries/automotive/", + "image": "/images/industries/automotive.jpg" + }, + "resources": { + "title": "Free Node-RED training", + "link": "https://node-red-academy.learnworlds.com/", + "image": "/images/education/education_hero.jpg" + }, + "company": { + "title": "See how teams ship with FlowFuse", + "link": "/customer-stories/", + "image": "/images/stories/arch_systems.jpeg" + } +} diff --git a/src/_includes/base.js b/src/_includes/base.js index d0536fc383..3f6872809d 100644 --- a/src/_includes/base.js +++ b/src/_includes/base.js @@ -164,3 +164,17 @@ function ffCreateHubSpotForm (config) { } window.ffCreateHubSpotForm = ffCreateHubSpotForm + +// Mobile nav: dropdown sections expand on tap, not hover +document.addEventListener('DOMContentLoaded', function () { + document.querySelectorAll('header .ff-nav-dropdown > span').forEach(function (trigger) { + trigger.addEventListener('click', function (e) { + if (window.innerWidth < 768) { + e.preventDefault() + e.stopPropagation() + // Toggle this section on its own; other open sections stay open + trigger.parentElement.classList.toggle('mobile-expanded') + } + }) + }) +}) diff --git a/src/_includes/components/events-banner.njk b/src/_includes/components/events-banner.njk deleted file mode 100644 index 0829f60ffa..0000000000 --- a/src/_includes/components/events-banner.njk +++ /dev/null @@ -1,76 +0,0 @@ -{% set colors = ["bg-indigo-700 hover:bg-indigo-600", "bg-indigo-800 hover:bg-indigo-700", "bg-indigo-900 hover:bg-indigo-800"] %} -{% set hasFutureEvents = false %} - -{% for event in events %} - {% if event.expire | isFutureDate %} - {% set hasFutureEvents = true %} - {% endif %} -{% endfor %} - -{% if hasFutureEvents %} - -{% endif %} - - diff --git a/src/_includes/components/flowfuse-square.svg b/src/_includes/components/flowfuse-square.svg index f117e04e8b..7ce1777f2d 100644 --- a/src/_includes/components/flowfuse-square.svg +++ b/src/_includes/components/flowfuse-square.svg @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/src/_includes/components/flowfuse-wordmark-footer.njk b/src/_includes/components/flowfuse-wordmark-footer.njk new file mode 100644 index 0000000000..38ebde749b --- /dev/null +++ b/src/_includes/components/flowfuse-wordmark-footer.njk @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/_includes/components/flowfuse-wordmark.njk b/src/_includes/components/flowfuse-wordmark.njk index cc886a85cb..6dba8f8275 100644 --- a/src/_includes/components/flowfuse-wordmark.njk +++ b/src/_includes/components/flowfuse-wordmark.njk @@ -1,4 +1,13 @@ + + + + + + + + + @@ -10,37 +19,37 @@ + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> + fill="url(#ffWaveWordmark)" /> diff --git a/src/_includes/components/icons/wind-turbine.svg b/src/_includes/components/icons/wind-turbine.svg index 4a4e3104f9..8a83fd49ad 100644 --- a/src/_includes/components/icons/wind-turbine.svg +++ b/src/_includes/components/icons/wind-turbine.svg @@ -1,4 +1,4 @@ - + diff --git a/src/_includes/components/industry-use-cases.njk b/src/_includes/components/industry-use-cases.njk new file mode 100644 index 0000000000..dc78f04250 --- /dev/null +++ b/src/_includes/components/industry-use-cases.njk @@ -0,0 +1,27 @@ +{# ============================================================ + USE CASES FOR THIS INDUSTRY - derived grid. + Lists every use-case page whose `industries[]` front-matter + contains the current page's fileSlug. Mapping source of truth: + the Use Cases Asana project (Industry field). + ============================================================ #} +{% set industrySlug = page.fileSlug %} +
    +
    +

    Use cases in {{ industryDisplayName or hero.eyebrow or title }}

    +

    Operational workflow patterns teams in this industry build and own with FlowFuse.

    +
    + {% for uc in collections["use-case"] | sort(false, true, "data.title") %} + {% if uc.data.industries and industrySlug in uc.data.industries %} + +

    {{ uc.data.title }}

    +

    {{ uc.data.problem }}

    + + View use case + {% include "components/icons/arrow-right.svg" %} + +
    + {% endif %} + {% endfor %} +
    +
    +
    diff --git a/src/_includes/components/nav-highlight.njk b/src/_includes/components/nav-highlight.njk new file mode 100644 index 0000000000..c66dca9bd0 --- /dev/null +++ b/src/_includes/components/nav-highlight.njk @@ -0,0 +1,13 @@ +{# Mega-dropdown highlight card: the linked page's marketing image with a + short title underneath. Expects `hl` set by the caller: + {% set hl = navHighlights.platform %}{% include "components/nav-highlight.njk" %} + Content is configured in src/_data/navHighlights.js (marketing-owned). + Card image: hl.image override, else the linked page's `image:` front + matter (its marketing image), else the generic og-blog fallback. #} +{% set hlImage = hl.image or (collections.all | pageImageForUrl(hl.link)) or "/images/og-blog.jpg" %} +
  • + + {{ hl.title }} + + +
  • diff --git a/src/_includes/components/related-resources.njk b/src/_includes/components/related-resources.njk index 9dea7522fd..4b0759e225 100644 --- a/src/_includes/components/related-resources.njk +++ b/src/_includes/components/related-resources.njk @@ -39,7 +39,7 @@ diff --git a/src/_includes/components/top-utility-bar.njk b/src/_includes/components/top-utility-bar.njk new file mode 100644 index 0000000000..572a0921b6 --- /dev/null +++ b/src/_includes/components/top-utility-bar.njk @@ -0,0 +1,78 @@ +{# Slim top utility bar: rotating announcements (left) + quick links (right). + Pattern adapted from tailscale.com's slim top bar. The announcement slot + rotates through any live events (same behaviour as the old events-banner) + plus the standing promos below. Implements the intent of website PR #5067. #} + + + diff --git a/src/_includes/components/use-case-chips.njk b/src/_includes/components/use-case-chips.njk new file mode 100644 index 0000000000..93e8e48e77 --- /dev/null +++ b/src/_includes/components/use-case-chips.njk @@ -0,0 +1,30 @@ +{# ============================================================ + USE CASE CONTEXT BAND - labeled links to the industry lens + pages. Reads `industries[]` (slugs) from page front-matter. + The slug->label maps mirror + the Use Cases Asana project fields (source of truth). + Rendered near the end of the use-case page, not under the hero. + ============================================================ #} +{% set industryLabels = { + "automotive": "Automotive", + "food-beverage": "Food & Beverage", + "life-sciences": "Life Sciences", + "aviation-aerospace": "Aviation & Aerospace", + "aerospace-components": "Aerospace Components", + "renewables": "Renewables", + "semiconductors": "Semiconductors", + "electronics-appliances": "Electronics & Appliances" +} %} +{% if industries %} +
    +
    + {% if industries %} + Common in these industries +

    + {% for slug in industries %}{{ industryLabels[slug] or slug }}{% if not loop.last %}, {% endif %}{% endfor %} + · all industries +

    + {% endif %} +
    +
    +{% endif %} diff --git a/src/_includes/components/use-case-links.njk b/src/_includes/components/use-case-links.njk new file mode 100644 index 0000000000..6ccc0867c2 --- /dev/null +++ b/src/_includes/components/use-case-links.njk @@ -0,0 +1,23 @@ +{# ============================================================ + USE CASE LINKS - systematic cross-link cards. + The host page declares which use cases to feature: + {% set featuredUseCases = ["slug-a", "slug-b"] %} + {% include "components/use-case-links.njk" %} + Card content (title, problem line, url) derives from each + use-case page's own front matter, so copy lives in one place. + ============================================================ #} +{% if featuredUseCases %} +
    + {% for slug in featuredUseCases %} + {% for uc in collections["use-case"] %} + {% if uc.fileSlug == slug %} + +

    {{ uc.data.title }}

    +

    {{ uc.data.problem }}

    + View use case {% include "components/icons/arrow-right.svg" %} +
    + {% endif %} + {% endfor %} + {% endfor %} +
    +{% endif %} diff --git a/src/_includes/explore-more-content.njk b/src/_includes/explore-more-content.njk index 6ae0c0a6af..281a5f258c 100644 --- a/src/_includes/explore-more-content.njk +++ b/src/_includes/explore-more-content.njk @@ -22,9 +22,9 @@ {%- endfor -%}
    - - See all - {% include "components/icons/arrow-long-right.svg" %} + + See all + {% include "components/icons/arrow-long-right.svg" %}
    diff --git a/src/_includes/layouts/base.njk b/src/_includes/layouts/base.njk index a6da57aa43..346fada9ae 100644 --- a/src/_includes/layouts/base.njk +++ b/src/_includes/layouts/base.njk @@ -163,20 +163,23 @@ eleventyComputed: Skip to main content -
    -
    - - {% include "../components/events-banner.njk" %} - -
    + + {% include "../components/top-utility-bar.njk" %} + +
    + +
    +
    {{ content | safe }} @@ -286,66 +365,181 @@ eleventyComputed: {% include "components/hm-promo-banner.njk" %}