diff --git a/_frontend/entrypoints/application.js b/_frontend/entrypoints/application.js index b9b1a75..e443c24 100644 --- a/_frontend/entrypoints/application.js +++ b/_frontend/entrypoints/application.js @@ -3,6 +3,7 @@ import SearchResults from "~/components/search/SearchResults.vue"; import SearchForm from "~/components/search/SearchForm.vue"; import { calculateWindowHeight } from "~/utils/styles"; import { loadMarketoForms } from "../utils/marketo"; +import { initAnnouncement, initAnnouncementButton } from "../utils/announcement"; const app = createApp({}); app.component("searchForm", SearchForm); @@ -12,6 +13,8 @@ app.mount("#main"); addEventListener("DOMContentLoaded", function () { calculateWindowHeight(); loadMarketoForms(); + initAnnouncement(); + initAnnouncementButton(); window.addEventListener("resize", calculateWindowHeight); }); diff --git a/_frontend/utils/announcement.js b/_frontend/utils/announcement.js new file mode 100644 index 0000000..ec38f3b --- /dev/null +++ b/_frontend/utils/announcement.js @@ -0,0 +1,68 @@ +import { getCookie, setCookie } from "./browser"; +import { hash } from "./str"; + +function getAnnouncementHash() { + const announcement = document.querySelector(".announcement"); + const content = announcement ? announcement.textContent || "" : ""; + const hashedContent = hash(content.trim().replace(/\n\t/, "")); + + return hashedContent; +} + +function hideAnnouncement() { + const announcement = document.querySelector(".announcement"); + + if (announcement) { + const content = getAnnouncementHash(); + setCookie("dismissed_announcement", content); + announcement.classList.add("d-none"); + } +} + +function showAnnouncement() { + const announcement = document.querySelector(".announcement"); + + if (announcement) { + announcement.classList.remove("d-none"); + } +} + +export function checkAnnounementStatus() { + const dismissedAnnouncement = getCookie("dismissed_announcement"); + const content = getAnnouncementHash(); + let isDismissed = false; + + if (dismissedAnnouncement === content) { + isDismissed = true; + } + + if (!isDismissed) { + showAnnouncement(); + } + + if (isDismissed) { + hideAnnouncement(); + } +} + +export function initAnnouncementButton() { + const button = document.querySelector(".announcement .close"); + + if (button) { + button.addEventListener("click", hideAnnouncement); + } +} + +export function initAnnouncement() { + const dismissedAnnouncement = getCookie("dismissed_announcement"); + const content = getAnnouncementHash(); + let isDismissed = false; + + if (dismissedAnnouncement === content) { + isDismissed = true; + } + + if (!isDismissed) { + showAnnouncement(); + } +} diff --git a/_frontend/utils/browser.js b/_frontend/utils/browser.js new file mode 100644 index 0000000..d9faf3d --- /dev/null +++ b/_frontend/utils/browser.js @@ -0,0 +1,35 @@ +/** + * Get Cookie + * Get a cookie from the browser + * + * @param {string} name + * @return {string | null} + */ +export function getCookie(name) { + if (typeof document === "undefined") { + return null; + } + const match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]+)")); + if (match && match[2]) return decodeURIComponent(match[2]); + return null; +} + +/** + * Set a cookie + * Set a cookie in browser + * @param {string} name + * @param {string} value + * @param {Date} expires + * @return {void} + */ +export function setCookie(name, value, expires) { + if (typeof document === "undefined") { + return; + } + const cookie = [`${name}=${value}`]; + if (expires) { + cookie.push(`expires=${expires.toUTCString()}`); + } + cookie.push(`path=/`); + document.cookie = cookie.join("; "); +} diff --git a/_frontend/utils/str.js b/_frontend/utils/str.js new file mode 100644 index 0000000..2b300ba --- /dev/null +++ b/_frontend/utils/str.js @@ -0,0 +1,7 @@ +export function hash(s) { + let h = 9; + for (let i = 0; i < s.length; i++) { + h = Math.imul(h ^ s.charCodeAt(i), 9 ** 9); + } + return (h ^ (h >>> 9)).toString(16); +} diff --git a/_includes/announcement.html b/_includes/announcement.html new file mode 100644 index 0000000..c4c4f8f --- /dev/null +++ b/_includes/announcement.html @@ -0,0 +1,10 @@ +
+

+ Preview the new Kaskada, embedded in Python. Easily build real-time AI applications in minutes. + Read more +

+ + +
diff --git a/_includes/header.html b/_includes/header.html index 14aa6dd..2dd2be7 100644 --- a/_includes/header.html +++ b/_includes/header.html @@ -1,4 +1,6 @@ +