Populate the client website template with catalog feature flags.

Extract always-on public/portal/UTM plus optional email_sms, directmail, blog, payments, social, and social_ai so new client sites can be bootstrapped from this seed.

Refs #1
Refs #2

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-26 07:55:26 -05:00
co-authored by Cursor
parent 45d0888d33
commit 787f0e48fb
297 changed files with 32534 additions and 3 deletions
@@ -0,0 +1,149 @@
/**
* Address autocomplete via Django /api/address-suggest/ (Nominatim proxy).
* Never calls Nominatim from the browser.
*
* Markup: wrap fields in [data-address-autocomplete][data-suggest-url="..."].
* Mark inputs with data-ac="line1|line2|city|state|zip|country".
* The line1 input is the typeahead trigger.
*/
(function () {
"use strict";
var DEBOUNCE_MS = 280;
var MIN_CHARS = 3;
function debounce(fn, wait) {
var t;
return function () {
var ctx = this;
var args = arguments;
clearTimeout(t);
t = setTimeout(function () {
fn.apply(ctx, args);
}, wait);
};
}
function field(root, key) {
return root.querySelector('[data-ac="' + key + '"]');
}
function ensureList(root) {
var list = root.querySelector(".address-ac-list");
if (list) {
return list;
}
list = document.createElement("ul");
list.className = "address-ac-list";
list.hidden = true;
list.setAttribute("role", "listbox");
var line1 = field(root, "line1");
var wrap = line1 && line1.closest(".form-wrap, .field");
(wrap || root).appendChild(list);
if (wrap) {
wrap.classList.add("address-ac-wrap");
} else {
root.classList.add("address-ac-wrap");
}
return list;
}
function hide(list) {
list.hidden = true;
list.innerHTML = "";
}
function fill(root, item) {
var map = {
line1: item.line1 || "",
line2: item.line2 || "",
city: item.city || "",
state: item.state || "",
zip: item.zip || "",
country: item.country || "US",
};
Object.keys(map).forEach(function (key) {
var el = field(root, key);
if (el) {
el.value = map[key];
el.dispatchEvent(new Event("input", { bubbles: true }));
el.dispatchEvent(new Event("change", { bubbles: true }));
}
});
}
function render(root, list, results) {
list.innerHTML = "";
if (!results.length) {
hide(list);
return;
}
results.forEach(function (item, index) {
var li = document.createElement("li");
li.className = "address-ac-item";
li.setAttribute("role", "option");
li.setAttribute("tabindex", "-1");
li.dataset.index = String(index);
li.textContent = item.label || item.line1 || "Address";
li.addEventListener("mousedown", function (ev) {
ev.preventDefault();
fill(root, item);
hide(list);
});
list.appendChild(li);
});
list.hidden = false;
}
function bind(root) {
var url = root.getAttribute("data-suggest-url");
var input = field(root, "line1");
if (!url || !input) {
return;
}
var list = ensureList(root);
input.setAttribute("autocomplete", "off");
input.setAttribute("aria-autocomplete", "list");
var fetchSuggest = debounce(function () {
var q = (input.value || "").trim();
if (q.length < MIN_CHARS) {
hide(list);
return;
}
var req = url + (url.indexOf("?") >= 0 ? "&" : "?") + "q=" + encodeURIComponent(q) + "&limit=5";
fetch(req, { headers: { Accept: "application/json" }, credentials: "same-origin" })
.then(function (res) {
return res.json();
})
.then(function (data) {
render(root, list, (data && data.results) || []);
})
.catch(function () {
hide(list);
});
}, DEBOUNCE_MS);
input.addEventListener("input", fetchSuggest);
input.addEventListener("keydown", function (ev) {
if (ev.key === "Escape") {
hide(list);
}
});
document.addEventListener("click", function (ev) {
if (!root.contains(ev.target)) {
hide(list);
}
});
}
function init() {
document.querySelectorAll("[data-address-autocomplete]").forEach(bind);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();
+299
View File
File diff suppressed because one or more lines are too long
+2092
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,161 @@
(function () {
'use strict';
var NOTICE_KEY = 'aiml_analytics_notice';
var LEGACY_CONSENT_KEY = 'aiml_analytics_consent';
var LEGACY_DISABLED_KEY = 'tianji.disabled';
var configEl = document.getElementById('tianji-config');
if (!configEl) {
return;
}
var trackerUrl = configEl.dataset.trackerUrl;
var websiteId = configEl.dataset.websiteId;
var userId = configEl.dataset.userId || '';
function getStorageItem(key) {
try {
return localStorage.getItem(key);
} catch (e) {
return null;
}
}
function setStorageItem(key, value) {
try {
localStorage.setItem(key, value);
} catch (e) {
/* ignore storage errors */
}
}
function removeStorageItem(key) {
try {
localStorage.removeItem(key);
} catch (e) {
/* ignore storage errors */
}
}
function showBanner() {
var banner = document.getElementById('cookie-consent-banner');
if (banner) {
banner.removeAttribute('hidden');
}
}
function hideBanner() {
var banner = document.getElementById('cookie-consent-banner');
if (banner) {
banner.setAttribute('hidden', '');
}
}
function trackEvent(name, data) {
if (window.tianji && typeof window.tianji.track === 'function') {
window.tianji.track(name, data || {});
}
}
function identifyUser() {
if (!userId || !window.tianji || typeof window.tianji.identify !== 'function') {
return;
}
window.tianji.identify({ userId: userId });
}
function loadTracker() {
if (document.querySelector('script[data-tianji-loaded="true"]')) {
identifyUser();
return;
}
var script = document.createElement('script');
script.async = true;
script.defer = true;
script.src = trackerUrl;
script.setAttribute('data-website-id', websiteId);
script.setAttribute('data-do-not-track', 'true');
script.setAttribute('data-tianji-loaded', 'true');
script.onload = function () {
identifyUser();
document.dispatchEvent(new CustomEvent('tianji:ready'));
};
document.head.appendChild(script);
}
function migrateLegacyConsent() {
var legacyConsent = getStorageItem(LEGACY_CONSENT_KEY);
var legacyDisabled = getStorageItem(LEGACY_DISABLED_KEY);
if (legacyConsent === 'accepted') {
setStorageItem(NOTICE_KEY, 'acknowledged');
removeStorageItem(LEGACY_CONSENT_KEY);
removeStorageItem(LEGACY_DISABLED_KEY);
return 'migrated_acknowledged';
}
if (legacyConsent === 'declined' || legacyDisabled === '1') {
removeStorageItem(LEGACY_CONSENT_KEY);
removeStorageItem(LEGACY_DISABLED_KEY);
return 'migrated_declined';
}
return null;
}
function acknowledgeNotice() {
setStorageItem(NOTICE_KEY, 'acknowledged');
hideBanner();
window.aimlTrackWhenReady('notice_acknowledged');
}
function bindBannerControls() {
var acknowledgeBtn = document.getElementById('cookie-consent-acknowledge');
var manageLinks = document.querySelectorAll('[data-open-cookie-preferences]');
if (acknowledgeBtn) {
acknowledgeBtn.addEventListener('click', acknowledgeNotice);
}
manageLinks.forEach(function (link) {
link.addEventListener('click', function (event) {
event.preventDefault();
showBanner();
});
});
}
window.aimlTrack = function (name, data) {
trackEvent(name, data);
};
window.aimlTrackWhenReady = function (name, data) {
if (window.tianji && typeof window.tianji.track === 'function') {
trackEvent(name, data);
return;
}
document.addEventListener('tianji:ready', function handler() {
document.removeEventListener('tianji:ready', handler);
trackEvent(name, data);
});
};
function initNotice() {
bindBannerControls();
loadTracker();
var migration = migrateLegacyConsent();
var notice = getStorageItem(NOTICE_KEY);
if (notice === 'acknowledged' || migration === 'migrated_acknowledged') {
hideBanner();
return;
}
showBanner();
}
initNotice();
})();