From 18ea764b3cb3f8db32d3dac72ff490f01a0f5f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cyndira-flowforge=E2=80=9D?= <“yndira@flowforge.com”> Date: Tue, 14 May 2024 17:06:51 +0200 Subject: [PATCH 1/3] Implemented Event Banner Rotation --- .eleventy.js | 2 + package-lock.json | 65 +++++++++---------- package.json | 1 + src/_data/events.yaml | 4 ++ src/_includes/components/events-banner.njk | 74 ++++++++++++++++++---- src/css/style.css | 27 ++++++++ 6 files changed, 128 insertions(+), 45 deletions(-) create mode 100644 src/_data/events.yaml diff --git a/.eleventy.js b/.eleventy.js index 3e85106c02..ee4005677c 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -20,11 +20,13 @@ const schema = require("@quasibit/eleventy-plugin-schema"); const imageHandler = require('./lib/image-handler.js') const site = require("./src/_data/site"); const coreNodeDoc = require("./lib/core-node-docs.js"); +const yaml = require("js-yaml"); // Skip slow optimizations when developing i.e. serve/watch or Netlify deploy preview const DEV_MODE = process.env.ELEVENTY_RUN_MODE !== "build" || process.env.CONTEXT === "deploy-preview" module.exports = function(eleventyConfig) { + eleventyConfig.addDataExtension("yaml", contents => yaml.load(contents)); // Add support for YAML data files eleventyConfig.setUseGitIgnore(false); // Otherwise docs are ignored // Set DEV_MODE_POSTS to true if the context is not 'production' diff --git a/package-lock.json b/package-lock.json index c151175bb3..f6eaca7e1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@quasibit/eleventy-plugin-schema": "^1.11.0", "@xmldom/xmldom": "^0.8.10", "codeowners": "^5.1.1", + "js-yaml": "^4.1.0", "markdown-it-attrs": "^4.1.6", "xml-js": "^1.6.11" }, @@ -1023,11 +1024,9 @@ "license": "MIT" }, "node_modules/argparse": { - "version": "1.0.10", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-differ": { "version": "3.0.0", @@ -2019,7 +2018,7 @@ }, "node_modules/ejs": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dependencies": { "jake": "^10.8.5" @@ -2195,7 +2194,8 @@ }, "node_modules/esprima": { "version": "4.0.1", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2651,6 +2651,26 @@ "node": ">=6.0" } }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/hamljs": { "version": "0.6.2" }, @@ -3342,11 +3362,11 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", - "license": "MIT", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -3667,10 +3687,6 @@ "dev": true, "license": "MIT" }, - "node_modules/markdown-it/node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0" - }, "node_modules/maximatch": { "version": "0.1.0", "license": "MIT", @@ -3904,11 +3920,6 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, "node_modules/mocha/node_modules/brace-expansion": { "version": "2.0.1", "dev": true, @@ -3938,17 +3949,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.0.1", "dev": true, @@ -5902,7 +5902,8 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/ssri": { "version": "8.0.1", diff --git a/package.json b/package.json index 1aab8c9e87..d80c803dbf 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@quasibit/eleventy-plugin-schema": "^1.11.0", "@xmldom/xmldom": "^0.8.10", "codeowners": "^5.1.1", + "js-yaml": "^4.1.0", "markdown-it-attrs": "^4.1.6", "xml-js": "^1.6.11" } diff --git a/src/_data/events.yaml b/src/_data/events.yaml new file mode 100644 index 0000000000..fe7988d734 --- /dev/null +++ b/src/_data/events.yaml @@ -0,0 +1,4 @@ +- type: "Webinar" + title: "Deploy FlowFuse on Industrial IoT with NCD.io" + buttonText: "Learn more" + link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" \ No newline at end of file diff --git a/src/_includes/components/events-banner.njk b/src/_includes/components/events-banner.njk index bf21ca99cc..21b1b675be 100644 --- a/src/_includes/components/events-banner.njk +++ b/src/_includes/components/events-banner.njk @@ -1,15 +1,63 @@ +{% set colors = ["bg-indigo-700 hover:bg-indigo-600", "bg-indigo-800 hover:bg-indigo-700", "bg-indigo-900 hover:bg-indigo-800"] %} + + + + window.onload = function() { + const banners = document.querySelectorAll('.event-banner'); + const container = document.querySelector('.event-banner-container'); + let currentBanner = 0; + + // Change the container color to match the current banner + function changeContainerColor(banner) { + const colorClass = banner.className.match(/bg-\w+-\d+/)[0]; + const hoverColorClass = banner.className.match(/hover:bg-\w+-\d+/)[0]; + container.className = 'event-banner-container ' + colorClass + ' ' + hoverColorClass + ' hidden sm:block'; + } + + // All banners are hidden by default + banners.forEach(banner => banner.style.visibility = 'hidden'); - + // Show the first banner + banners[0].style.visibility = 'visible'; + changeContainerColor(banners[0]); + + // If there is more than one banner, change the visible banner every 5 seconds + if (banners.length > 1) { + setInterval(function() { + // Hide the current banner + banners[currentBanner].style.visibility = 'hidden'; + + // Increment the current banner index + currentBanner = (currentBanner + 1) % banners.length; + + // Show the new banner + banners[currentBanner].style.visibility = 'visible'; + banners[currentBanner].style.animation = 'none'; // reset animation + // force reflow, triggering a new animation + void banners[currentBanner].offsetWidth; + banners[currentBanner].style.animation = 'slideDown 0.5s ease'; + + // Change the container color to match the new banner + setTimeout(function() { + changeContainerColor(banners[currentBanner]); + }, 500); // wait for the slideDown animation to finish + }, 7000); + } + }; + diff --git a/src/css/style.css b/src/css/style.css index 71f06302c3..29e9b6e3bf 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -203,6 +203,33 @@ dl.message-properties { @apply m-auto text-center sm:text-left p-8 max-w-md sm:max-w-screen-lg bg-indigo-50 border border-white rounded-lg mt-6; } +/* + Event banner +*/ +.event-banner-container { + position: relative; + height: 44px; + width: 100%; +} + +.event-banner { + position: absolute; + top: 0; + left: 0; + width: 100%; + visibility: hidden; + animation: slideDown 0.5s ease-in-out; +} + +.event-banner:first-child { + visibility: visible; +} + +@keyframes slideDown { + 0% { transform: translateY(-100%); } + 100% { transform: translateY(0); } +} + /* Blog */ From b1c7c08386ccdac37356f8be31dc703b53cfa283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cyndira-flowforge=E2=80=9D?= <“yndira@flowforge.com”> Date: Tue, 14 May 2024 17:23:47 +0200 Subject: [PATCH 2/3] Update handbook --- src/handbook/customer/marketing/website.md | 29 +++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/handbook/customer/marketing/website.md b/src/handbook/customer/marketing/website.md index ca34ae64f5..ae283ff6a2 100644 --- a/src/handbook/customer/marketing/website.md +++ b/src/handbook/customer/marketing/website.md @@ -12,16 +12,33 @@ navTitle: Marketing - Website ## Events Banner -To update the event banner that appears at the top of the Website, you will need two pieces of information: +The event banner at the top of the website can display more than one event or announcement. -- The title of the Webinar -- URL that the Webinar Registration is hosted at +To add or update an event, you'll need to modify the [following file](https://github.com/FlowFuse/website/blob/main/src/_data/events.yaml). The information should be formatted as follows for each banner: -Once you have those, you can update the [following file](https://github.com/FlowFuse/website/blob/main/src/_includes/components/events-banner.njk): +``` +- type: "Webinar" + title: "Deploy FlowFuse on Industrial IoT with NCD.io" + buttonText: "Learn more" + link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" +``` + +If there were more than one event, then duplicating that and updating the info will create the second banner for rotation. It would look like this: + +``` +- type: "Webinar" + title: "Deploy FlowFuse on Industrial IoT with NCD.io" + buttonText: "Learn more" + link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" +- type: "New Release" + title: "FlowFuse 2.4: making it easier to work with Snapshots, Blueprints & Devices " + buttonText: "See blog post" + link: "/blog/2024/05/flowfuse-2-4-release/" +``` -Update the `href=""` value of the `` tag to update the Event URL, and change the title inside the middle `` +If there is only one event, the banner will continuously display that event. If there are multiple events, the banner will rotate through them, displaying each one for a few seconds at a time. -You should also ensure that the banner is not disabled in [this file](https://github.com/FlowFuse/website/blob/main/src/_includes/layouts/base.njk). If it is, it would look like this: +Please also ensure that the banner is not disabled in [this file](https://github.com/FlowFuse/website/blob/main/src/_includes/layouts/base.njk). If it is, the code would look like this: `{% raw %} {# {% include "../components/events-banner.njk" %} #} {% endraw %}`. Please remove the comment symbols `{#` and `#}` to enable the banner. From 4c418d7570f693d9b511169a2b43ac9c4eb0f851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cyndira-flowforge=E2=80=9D?= <“yndira@flowforge.com”> Date: Wed, 15 May 2024 12:57:01 +0200 Subject: [PATCH 3/3] Add expiration functionality to event banners --- .eleventy.js | 3 +- .github/workflows/build.yml | 1 + src/_data/events.yaml | 3 +- src/_includes/components/events-banner.njk | 39 ++++++++++++++-------- src/_includes/layouts/base.njk | 2 +- src/handbook/customer/marketing/website.md | 13 +++++--- 6 files changed, 40 insertions(+), 21 deletions(-) diff --git a/.eleventy.js b/.eleventy.js index ee4005677c..a13b96f5c7 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -46,7 +46,8 @@ module.exports = function(eleventyConfig) { }); // Define a filter named 'isFutureDate' - eleventyConfig.addFilter('isFutureDate', (date) => { + eleventyConfig.addFilter('isFutureDate', (dateString) => { + const date = new Date(dateString); return date && date > new Date(); }); diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 53f8273a92..b3073a4e29 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,7 @@ on: - main schedule: - cron: "30 9 * * *" + - cron: "5 16 * * 3,4" jobs: build_deploy: if: ${{ github.repository == 'FlowFuse/website' }} diff --git a/src/_data/events.yaml b/src/_data/events.yaml index fe7988d734..531cdb2588 100644 --- a/src/_data/events.yaml +++ b/src/_data/events.yaml @@ -1,4 +1,5 @@ - type: "Webinar" title: "Deploy FlowFuse on Industrial IoT with NCD.io" buttonText: "Learn more" - link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" \ No newline at end of file + link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" + expire: "2024-05-29T16:00:00Z" \ No newline at end of file diff --git a/src/_includes/components/events-banner.njk b/src/_includes/components/events-banner.njk index 21b1b675be..0829f60ffa 100644 --- a/src/_includes/components/events-banner.njk +++ b/src/_includes/components/events-banner.njk @@ -1,26 +1,39 @@ {% 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/layouts/base.njk b/src/_includes/layouts/base.njk index 05ca679d2b..d42a72d2e5 100644 --- a/src/_includes/layouts/base.njk +++ b/src/_includes/layouts/base.njk @@ -161,7 +161,7 @@ eleventyComputed:
- + {% include "../components/events-banner.njk" %}
diff --git a/src/handbook/customer/marketing/website.md b/src/handbook/customer/marketing/website.md index ae283ff6a2..f8fac668e8 100644 --- a/src/handbook/customer/marketing/website.md +++ b/src/handbook/customer/marketing/website.md @@ -21,7 +21,13 @@ To add or update an event, you'll need to modify the [following file](https://gi title: "Deploy FlowFuse on Industrial IoT with NCD.io" buttonText: "Learn more" link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" + expire: "2024-05-29T16:00:00Z" ``` +The `expire` field is used to set the date and time when the event should stop being displayed on the banner. The date and time are set in the ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`, and the time is in Coordinated Universal Time (UTC). + +For example, `expire: "2024-05-29T15:00:00Z"` means that the event will stop being displayed on the banner at 16:00 UTC on May 29, 2024. + +Please note that the website is built once a day at 9:30 AM UTC, and also on Wednesdays and Thursdays at 16:05 UTC. This means that if an event expires at some point during the day, it will still be displayed until the next time the website is built. If there were more than one event, then duplicating that and updating the info will create the second banner for rotation. It would look like this: @@ -30,19 +36,16 @@ If there were more than one event, then duplicating that and updating the info w title: "Deploy FlowFuse on Industrial IoT with NCD.io" buttonText: "Learn more" link: "/webinars/2024/deploy-flowfuse-on-industrial-iot-with-ncd-io/" + expire: "2024-05-29T15:00:00Z" - type: "New Release" title: "FlowFuse 2.4: making it easier to work with Snapshots, Blueprints & Devices " buttonText: "See blog post" link: "/blog/2024/05/flowfuse-2-4-release/" + expire: "2024-05-20T15:00:00Z" ``` If there is only one event, the banner will continuously display that event. If there are multiple events, the banner will rotate through them, displaying each one for a few seconds at a time. -Please also ensure that the banner is not disabled in [this file](https://github.com/FlowFuse/website/blob/main/src/_includes/layouts/base.njk). If it is, the code would look like this: -`{% raw %} -{# {% include "../components/events-banner.njk" %} #} -{% endraw %}`. Please remove the comment symbols `{#` and `#}` to enable the banner. - ## Images All images on the website, whether part of the blog or otherwise, are run though an [image pipeline](https://github.com/FlowFuse/website/blob/main/lib/image-handler.js), that compresses, resizes and converts the images to reduce file size and improve page loading speed.