Add viator-collector plugin (Hop On Hop Off front-end reskin)
Consolidate the plugin into the TourWebsite repository (its separate nested git repo has been removed). Includes the full new-design reskin: scoped design stylesheet, SVG icon sprite, rebuilt listing/single/section templates, and homepage hero/FAQ/testimonials shortcodes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J4hNL1PSHxXbu94SCenpKj
This commit is contained in:
95
viator-collector/assets/js/vc-design.js
Normal file
95
viator-collector/assets/js/vc-design.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/* Viator Collector — front-end interactions for the "Hop On Hop Off" design.
|
||||
Ported from the mockup's main.js, trimmed to what the plugin renders inside
|
||||
#vc-app. Listing filtering itself stays server-side (GET form submit); this
|
||||
file only adds UX: card rails, FAQ accordion, testimonials marquee, the date
|
||||
field, and auto-submit on quick filter toggles. */
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// The design is scoped to .vc-app wrappers; there can be several on one page
|
||||
// (e.g. multiple homepage section shortcodes), so query document-wide.
|
||||
var app = document;
|
||||
|
||||
/* ---------- card rails (prev / next) ---------- */
|
||||
function railStep(rail) {
|
||||
var card = rail.firstElementChild;
|
||||
if (!card) return rail.clientWidth;
|
||||
var gap = parseFloat(getComputedStyle(rail).columnGap) || 0;
|
||||
return card.getBoundingClientRect().width + gap;
|
||||
}
|
||||
|
||||
function syncRailButtons(rail, prev, next) {
|
||||
var max = rail.scrollWidth - rail.clientWidth - 1;
|
||||
if (prev) prev.disabled = rail.scrollLeft <= 0;
|
||||
if (next) next.disabled = rail.scrollLeft >= max;
|
||||
}
|
||||
|
||||
Array.prototype.forEach.call(app.querySelectorAll(".rail"), function (rail) {
|
||||
var prev = document.querySelector('[data-rail-prev="' + rail.id + '"]');
|
||||
var next = document.querySelector('[data-rail-next="' + rail.id + '"]');
|
||||
|
||||
if (prev) prev.addEventListener("click", function () {
|
||||
rail.scrollBy({ left: -railStep(rail), behavior: "smooth" });
|
||||
});
|
||||
if (next) next.addEventListener("click", function () {
|
||||
rail.scrollBy({ left: railStep(rail), behavior: "smooth" });
|
||||
});
|
||||
|
||||
rail.addEventListener("scroll", function () {
|
||||
syncRailButtons(rail, prev, next);
|
||||
}, { passive: true });
|
||||
window.addEventListener("resize", function () {
|
||||
syncRailButtons(rail, prev, next);
|
||||
});
|
||||
syncRailButtons(rail, prev, next);
|
||||
});
|
||||
|
||||
/* ---------- testimonials marquee: duplicate for a seamless loop ---------- */
|
||||
Array.prototype.forEach.call(app.querySelectorAll("[data-marquee] .marquee__track"), function (track) {
|
||||
Array.prototype.slice.call(track.children).forEach(function (node) {
|
||||
var copy = node.cloneNode(true);
|
||||
copy.setAttribute("aria-hidden", "true");
|
||||
track.appendChild(copy);
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- FAQ accordion ---------- */
|
||||
Array.prototype.forEach.call(app.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";
|
||||
Array.prototype.forEach.call(accordion.querySelectorAll(".acc__q"), function (other) {
|
||||
other.setAttribute("aria-expanded", "false");
|
||||
});
|
||||
btn.setAttribute("aria-expanded", String(!open));
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- date field: text placeholder, native picker on focus ---------- */
|
||||
Array.prototype.forEach.call(app.querySelectorAll("[data-datefield]"), function (dateField) {
|
||||
dateField.addEventListener("focus", function () {
|
||||
dateField.type = "date";
|
||||
if (typeof dateField.showPicker === "function") {
|
||||
try { dateField.showPicker(); } catch (err) { /* not user-activated */ }
|
||||
}
|
||||
});
|
||||
dateField.addEventListener("blur", function () {
|
||||
if (!dateField.value) dateField.type = "text";
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- listing: auto-submit on quick toggles (checks / sort) ---------- */
|
||||
Array.prototype.forEach.call(app.querySelectorAll("form.filters, form#vc-filter-form"), function (form) {
|
||||
form.addEventListener("change", function (e) {
|
||||
if (e.target.closest(".vc-autosubmit")) form.submit();
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- single tour: "view all photos" scrolls the gallery ---------- */
|
||||
var viewAll = app.querySelector(".tg-viewall, .gallery__viewall");
|
||||
if (viewAll) viewAll.addEventListener("click", function () {
|
||||
var g = app.querySelector(".gallery, .tour-gallery");
|
||||
if (g) g.scrollIntoView({ behavior: "smooth" });
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user