feat(theme): About, Contact, FAQ, blog list and post pages from new front
- Route pages by address to theme templates (about-us, contact-us, faq, blogs, posts) - Scoped design CSS (pages.css) + Astra/WordPress fixes (pages-wp.css), page JS - Contact form emails the new Settings -> Viator Collector -> Contact email (fallback: admin email), Reply-To the visitor, honeypot spam trap - Blog list shows real posts with search, sort and paging; posts use the article design with comments as reviews and related articles - Design images converted to WebP (~15MB PNG -> ~1MB) - Theme 1.0.10, plugin 1.9.1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
175
astra-child-hoponhopoff/assets/pages.js
Normal file
175
astra-child-hoponhopoff/assets/pages.js
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Behaviour for the theme's design pages (About, Contact, FAQ, blog list and
|
||||
* post) — the parts of "new front/js/main.js" these pages use. Header/footer
|
||||
* behaviour stays in chrome.js.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var cfg = window.hohoPages || {};
|
||||
var page = document.querySelector('main.hoho-page');
|
||||
if (!page) return;
|
||||
|
||||
var each = function (list, fn) { Array.prototype.forEach.call(list, fn); };
|
||||
|
||||
/* ---------- testimonials marquee: duplicate for a seamless loop ---------- */
|
||||
var marquee = page.querySelector('[data-marquee] .marquee__track');
|
||||
if (marquee) {
|
||||
each(Array.prototype.slice.call(marquee.children), function (node) {
|
||||
var copy = node.cloneNode(true);
|
||||
copy.setAttribute('aria-hidden', 'true');
|
||||
marquee.appendChild(copy);
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- FAQ accordion ---------- */
|
||||
each(page.querySelectorAll('[data-accordion]'), function (accordion) {
|
||||
accordion.addEventListener('click', function (e) {
|
||||
var btn = e.target.closest('.acc__q');
|
||||
if (!btn) return;
|
||||
var open = btn.getAttribute('aria-expanded') === 'true';
|
||||
each(accordion.querySelectorAll('.acc__q'), function (other) {
|
||||
other.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
btn.setAttribute('aria-expanded', String(!open));
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- FAQ page: category nav follows the scroll ---------- */
|
||||
var catLinks = Array.prototype.slice.call(page.querySelectorAll('.catnav__link'));
|
||||
if (catLinks.length && 'IntersectionObserver' in window) {
|
||||
var setCat = function (id) {
|
||||
catLinks.forEach(function (a) {
|
||||
var on = a.getAttribute('href') === '#' + id;
|
||||
a.classList.toggle('is-active', on);
|
||||
if (on) a.setAttribute('aria-current', 'true');
|
||||
else a.removeAttribute('aria-current');
|
||||
});
|
||||
};
|
||||
var catObserver = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.isIntersecting) setCat(entry.target.id);
|
||||
});
|
||||
}, { rootMargin: '-30% 0px -60% 0px' });
|
||||
catLinks.forEach(function (a) {
|
||||
var target = document.querySelector(a.getAttribute('href'));
|
||||
if (target) catObserver.observe(target);
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- blog list: sort applies on change ---------- */
|
||||
each(page.querySelectorAll('select[data-autosubmit]'), function (select) {
|
||||
select.addEventListener('change', function () { select.form.submit(); });
|
||||
});
|
||||
|
||||
/* ---------- single article: share links, copy link, more reviews ---------- */
|
||||
var post = document.getElementById('post');
|
||||
if (post) {
|
||||
var pageUrl = encodeURIComponent(window.location.href.split('#')[0]);
|
||||
var shareTargets = {
|
||||
telegram: 'https://t.me/share/url?url=',
|
||||
facebook: 'https://www.facebook.com/sharer/sharer.php?u=',
|
||||
whatsapp: 'https://wa.me/?text='
|
||||
};
|
||||
each(post.querySelectorAll('[data-share]'), function (a) {
|
||||
var base = shareTargets[a.getAttribute('data-share')];
|
||||
if (base) a.href = base + pageUrl;
|
||||
});
|
||||
|
||||
var copyBtn = post.querySelector('[data-copy-link]');
|
||||
if (copyBtn && navigator.clipboard) {
|
||||
var copyLabel = copyBtn.textContent;
|
||||
copyBtn.addEventListener('click', function () {
|
||||
navigator.clipboard.writeText(window.location.href.split('#')[0]).then(function () {
|
||||
copyBtn.textContent = cfg.copied || 'Link copied';
|
||||
copyBtn.classList.add('is-done');
|
||||
window.setTimeout(function () {
|
||||
copyBtn.textContent = copyLabel;
|
||||
copyBtn.classList.remove('is-done');
|
||||
}, 2000);
|
||||
}, function () {});
|
||||
});
|
||||
}
|
||||
|
||||
var reviewList = document.getElementById('reviewList');
|
||||
var reviewMore = document.getElementById('reviewMore');
|
||||
if (reviewList && reviewMore) {
|
||||
var moreLabel = reviewMore.querySelector('span');
|
||||
reviewMore.addEventListener('click', function () {
|
||||
var open = reviewList.classList.toggle('is-collapsed') === false;
|
||||
reviewMore.setAttribute('aria-expanded', String(open));
|
||||
moreLabel.textContent = open ? cfg.fewer : cfg.more;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- contact form: validate, then send without leaving the page ---------- */
|
||||
var ticketForm = document.getElementById('ticketForm');
|
||||
var ticketStatus = document.getElementById('ticketStatus');
|
||||
if (ticketForm && ticketStatus && window.fetch && window.FormData) {
|
||||
var submitBtn = ticketForm.querySelector('[type="submit"]');
|
||||
ticketForm.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var bad = null;
|
||||
each(ticketForm.querySelectorAll('.rinput'), function (field) {
|
||||
var ok = field.value.trim() !== '' && field.checkValidity();
|
||||
field.setAttribute('aria-invalid', String(!ok));
|
||||
if (!ok && !bad) bad = field;
|
||||
});
|
||||
ticketStatus.classList.toggle('is-error', !!bad);
|
||||
if (bad) {
|
||||
ticketStatus.textContent = cfg.invalid;
|
||||
bad.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
ticketStatus.textContent = cfg.sending;
|
||||
submitBtn.disabled = true;
|
||||
fetch(ticketForm.getAttribute('data-ajax'), { method: 'POST', credentials: 'same-origin', body: new FormData(ticketForm) })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var ok = res && res.success;
|
||||
ticketStatus.classList.toggle('is-error', !ok);
|
||||
ticketStatus.textContent = (res && res.data && res.data.message) || cfg.failed;
|
||||
if (ok) ticketForm.reset();
|
||||
})
|
||||
.catch(function () {
|
||||
ticketStatus.classList.add('is-error');
|
||||
ticketStatus.textContent = cfg.failed;
|
||||
})
|
||||
.then(function () { submitBtn.disabled = false; });
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- scroll reveal: sections fade/rise in, cards cascade after ---------- */
|
||||
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
if (!reduceMotion && 'IntersectionObserver' in window) {
|
||||
var sections = Array.prototype.slice.call(page.querySelectorAll(':scope > section, :scope > article, :scope > div.section'));
|
||||
var cardSelector = '.dcard, .acard, .titem, .rcard, .quote, .statcard';
|
||||
var groupCounts = new Map();
|
||||
|
||||
sections.forEach(function (section) {
|
||||
section.classList.add('reveal');
|
||||
each(section.querySelectorAll(cardSelector), function (card) {
|
||||
var group = card.parentElement;
|
||||
var i = groupCounts.get(group) || 0;
|
||||
groupCounts.set(group, i + 1);
|
||||
card.classList.add('reveal-item');
|
||||
card.style.animationDelay = (Math.min(i, 7) * 0.07) + 's';
|
||||
});
|
||||
});
|
||||
|
||||
var revealObserver = new IntersectionObserver(function (entries, obs) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) return;
|
||||
entry.target.classList.add('is-visible');
|
||||
each(entry.target.querySelectorAll('.reveal-item'), function (item) {
|
||||
item.classList.add('is-visible');
|
||||
});
|
||||
obs.unobserve(entry.target);
|
||||
});
|
||||
}, { threshold: 0.15, rootMargin: '0px 0px -8% 0px' });
|
||||
|
||||
sections.forEach(function (section) { revealObserver.observe(section); });
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user