Files
trades-starter/js/main.js
T
pauljd f2cc99dd94
pauljd/davidson-ci: Davidson CI / quality (push) Successful in 1m35s
pauljd/davidson-ci: Davidson CI / ai-review (push) Successful in 29s
Initial trades demo starter
2026-09-30 17:41:50 +01:00

130 lines
4.9 KiB
JavaScript

const text = (selector, value) => {
const element = document.querySelector(selector);
if (element) element.textContent = value ?? "";
};
const setLink = (selector, href, label) => {
const element = document.querySelector(selector);
if (!element) return;
element.href = href;
element.textContent = label;
};
const addText = (parent, tag, className, value) => {
const element = document.createElement(tag);
element.className = className;
element.textContent = value;
parent.append(element);
return element;
};
const renderBusiness = (business) => {
document.title = business.metaTitle;
document.querySelector('meta[name="description"]').content =
business.metaDescription;
text(".brand-name", business.name);
text(".footer-brand", business.name);
text(".header-call-label", business.headerCallLabel);
text(".header-phone", business.phoneDisplay);
text("[data-nav-services]", business.navigation.services);
text("[data-nav-about]", business.navigation.about);
text("[data-nav-contact]", business.navigation.contact);
const brand = document.querySelector(".brand");
brand.setAttribute("aria-label", business.homeLabel);
const logo = document.querySelector(".brand-logo");
if (business.logo) {
logo.src = business.logo;
logo.alt = business.logoAlt || business.name;
logo.hidden = false;
}
document.querySelectorAll("[data-phone-link]").forEach((link) => {
link.href = `tel:${business.phone.replace(/[^\d+]/g, "")}`;
});
setLink(
".hero-primary",
`tel:${business.phone.replace(/[^\d+]/g, "")}`,
business.hero.primaryAction,
);
setLink(".hero-secondary", "#services", business.hero.secondaryAction);
text(".hero-eyebrow", business.hero.eyebrow);
text(".hero-title", business.hero.title);
text(".hero-description", business.hero.description);
text(".hero-proof", "");
const proof = document.querySelector(".hero-proof");
business.highlights.forEach((item) => addText(proof, "span", "", item));
const heroImage = document.querySelector(".hero-image");
heroImage.src = business.hero.image;
heroImage.alt = business.hero.imageAlt;
text(".services-eyebrow", business.servicesSection.eyebrow);
text(".services-title", business.servicesSection.title);
text(".services-intro", business.servicesSection.description);
const serviceList = document.querySelector(".service-list");
business.services.forEach((service, index) => {
const item = document.createElement("article");
item.className = "service-item";
addText(item, "span", "service-index", String(index + 1).padStart(2, "0"));
addText(item, "h3", "", service.name);
addText(item, "p", "", service.description);
serviceList.append(item);
});
text(".about-marker .about-number", business.about.number);
text(".about-eyebrow", business.about.eyebrow);
text(".about-title", business.about.title);
text(".about-description", business.about.description);
setLink(".about-link", "#contact", business.about.linkLabel);
text(".about-quote", business.about.quote);
text(".about-quote-byline", business.about.quoteByline);
text(".contact-eyebrow", business.contact.eyebrow);
text(".contact-title", business.contact.title);
text(".contact-description", business.contact.description);
const contactPhone = document.querySelector(".contact-phone");
contactPhone.href = `tel:${business.phone.replace(/[^\d+]/g, "")}`;
contactPhone.textContent = business.contact.phoneLabel;
setLink(".contact-email", `mailto:${business.email}`, business.email);
text(".contact-location-label", business.contact.locationLabel);
text(".contact-address", business.location);
text(".contact-hours", business.hours);
text(".footer-location", business.location);
text(".footer-copyright", `© ${new Date().getFullYear()} ${business.name}`);
};
const menuToggle = document.querySelector(".menu-toggle");
const navigation = document.querySelector(".main-nav");
menuToggle.addEventListener("click", () => {
const isOpen = menuToggle.getAttribute("aria-expanded") === "true";
menuToggle.setAttribute("aria-expanded", String(!isOpen));
menuToggle.setAttribute(
"aria-label",
isOpen ? "Open navigation" : "Close navigation",
);
navigation.classList.toggle("is-open", !isOpen);
});
navigation.addEventListener("click", (event) => {
if (event.target.closest("a")) {
navigation.classList.remove("is-open");
menuToggle.setAttribute("aria-expanded", "false");
menuToggle.setAttribute("aria-label", "Open navigation");
}
});
fetch("data/business.json")
.then((response) => {
if (!response.ok)
throw new Error(`Could not load business config: ${response.status}`);
return response.json();
})
.then(renderBusiness)
.catch((error) => {
console.error(error);
document.body.innerHTML =
'<main class="config-error"><h1>Business details could not be loaded.</h1><p>Run this site from a local web server and check data/business.json.</p></main>';
});