PageSourceSearch

https://www.techmarcos.com/wp-content/themes/techmarcos/assets/js/modules/ui/interactive-cards.js

js techmarcos.com collected 2026-10-06 14:18:04 UTC 2,504 bytes, 89 lines download raw bytes

1/**
2 * Horizontal card/tab centring (the "our approach" cards + the logo tab strip).
3 *
4 * These live in reusable sections (templates/sections/our-approach-section.php,
5 * tab-logo.php), so they are guarded by markup presence rather than a page
6 * template — they activate wherever their section is rendered.
7 *
8 * - Center-active card: on mobile (<= 576px), as `#approach-cards` scrolls
9 *   horizontally, marks the card nearest the viewport centre `.active`.
10 * - Logo-tab: on load, scrolls the active `.logo-tab .nav-link` into the centre.
11 *
12 * @module ui/interactive-cards
13 */
14import { rafThrottle } from "../core/raf.js";
15import { onResize } from "./events.js";
16
17const $ = window.jQuery;
18const $window = $(window);
19const NS = ".tmCards";
20const CENTER_CARD_MAX_WIDTH = 576;
21
22/** Cached center-card state (module singleton). */
23const centerCards = { $container: $(), $boxes: $() };
24
25function updateCenterActiveBox() {
26  const { $container, $boxes } = centerCards;
27  if (
28    !$container.length ||
29    !$boxes.length ||
30    window.innerWidth > CENTER_CARD_MAX_WIDTH
31  ) {
32    return;
33  }
34
35  const center = $window.width() / 2;
36  let $closest = $();
37  let closestDistance = Infinity;
38
39  $boxes.each(function () {
40    const rect = this.getBoundingClientRect();
41    const boxCenter = rect.left + rect.width / 2;
42    const distance = Math.abs(center - boxCenter);
43    if (distance < closestDistance) {
44      closestDistance = distance;
45      $closest = $(this);
46    }
47  });
48
49  $boxes.removeClass("active");
50  $closest.addClass("active");
51}
52
53function initCenterActiveCard() {
54  const $container = $("#approach-cards");
55  const $boxes = $container.find(".theme-box");
56  if (!$container.length || !$boxes.length) return;
57
58  centerCards.$container = $container;
59  centerCards.$boxes = $boxes;
60
61  $container
62    .off(`scroll${NS}`)
63    .on(`scroll${NS}`, rafThrottle(updateCenterActiveBox));
64  onResize(updateCenterActiveBox);
65  updateCenterActiveBox();
66}
67
68function initLogoTabCentering() {
69  const $activeTab = $(".logo-tab .nav-link.active");
70  const $scrollContainer = $(".logo-tab");
71  if (!$activeTab.length || !$scrollContainer.length) return;
72
73  $scrollContainer[0].scrollTo({
74    left:
75      $activeTab[0].offsetLeft -
76      $scrollContainer.width() / 2 +
77      $activeTab.outerWidth() / 2,
78    behavior: "smooth",
79  });
80}
81
82/** @type {import("../core/registry.js").Component} */
83export default {
84  name: "interactive-cards",
85  init() {
86    initCenterActiveCard();
87    initLogoTabCentering();
88  },
89};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.