PageSourceSearch

https://phodu.club/redesign/legacy.js?v=1

js phodu.club collected 2026-10-03 02:29:43 UTC 7,286 bytes, 158 lines download raw bytes

1/*
2 * Restyle layer for captured WordPress/Elementor pages — the parts that depend
3 * on computed colours, so they can't be plain CSS (see legacy.css):
4 *   1. Buttons get a redesign variant: primary (lilac pill), light, or ghost.
5 *   2. The old white cards (testimonials, reviews, FAQ boxes) become dark
6 *      cards, and dark text inside them is lifted to the light text colour.
7 * Re-runs for nodes added later (carousels clone their slides).
8 */
9(() => {
10  const body = document.body;
11  if (!body || !body.classList.contains("pcx-legacy") || body.dataset.pcxRestyled) return;
12  body.dataset.pcxRestyled = "1";
13
14  const SKIP = ".pcx-hdr, .pcx-ftr, .pc-wl-popup, astro-dev-toolbar";
15  const BTN =
16    "a.elementor-button, button.elementor-button, .elementor-button-link, .wp-block-button__link, .wp-element-button, a.ekit-btn, .elementskit-btn, a.eael-creative-button, .ast-button, a.button, button.button";
17
18  const rgba = (c) => {
19    const m = /rgba?\(([^)]+)\)/.exec(c || "");
20    if (!m) return null;
21    const [r, g, b, a = 1] = m[1].split(/[\s,/]+/).filter(Boolean).map(Number);
22    return { r, g, b, a };
23  };
24  const lum = (c) => (0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) / 255;
25
26  const classifyButton = (el) => {
27    if (el.closest(SKIP) || el.classList.contains("pcx-btn")) return;
28    const cs = getComputedStyle(el);
29    const bg = rgba(cs.backgroundColor);
30    const hasGradient = /gradient/.test(cs.backgroundImage);
31    let variant = "primary";
32    if (!hasGradient) {
33      if (!bg || bg.a < 0.25) variant = "ghost";
34      else if (lum(bg) > 0.82) variant = "light";
35    }
36    el.classList.add("pcx-btn", `pcx-btn--${variant}`);
37  };
38
39  const CARD_TAGS = "div, section, article, aside, li, figure, blockquote, details, form, table";
40  const flipCard = (el) => {
41    if (el.closest(SKIP) || el.closest(".pcx-darkcard") || el.matches(BTN) || el.closest(".pcx-btn")) return;
42    const cs = getComputedStyle(el);
43    const bg = rgba(cs.backgroundColor);
44    if (!bg || bg.a < 0.85 || lum(bg) < 0.88) return;
45    if (el.offsetWidth < 120 || el.offsetHeight < 48) return;
46    el.classList.add("pcx-darkcard");
47    // Lift dark text inside the flipped card.
48    el.querySelectorAll("*").forEach((child) => {
49      const c = rgba(getComputedStyle(child).color);
50      if (c && lum(c) < 0.6) child.style.setProperty("color", "#e5e1f0", "important");
51    });
52    const own = rgba(cs.color);
53    if (own && lum(own) < 0.6) el.style.setProperty("color", "#e5e1f0", "important");
54  };
55
56  // The old site washed sections in violet glows/gradients; the redesign keeps
57  // surfaces flat with at most a faint lilac glow from the top.
58  const ACCENTS = /rgba?\(\s*(184,\s*118,\s*209|227,\s*159,\s*246|142,\s*86,\s*160|243,\s*217,\s*250)/;
59  const SOFT_GLOW = "radial-gradient(ellipse 60% 55% at 50% 0%, rgba(227, 159, 246, 0.09), transparent 70%)";
60  const isAccentWash = (cs) => {
61    const img = cs.backgroundImage;
62    if (!img || img === "none" || !/gradient/.test(img) || /url\(/.test(img) || !ACCENTS.test(img)) return false;
63    if (cs.webkitBackgroundClip === "text" || cs.backgroundClip === "text") return false;
64    // Gradient borders (padding-box + border-box layer pairs) are handled in CSS.
65    return !/padding-box/.test(cs.backgroundClip);
66  };
67  const softenGlow = (el) => {
68    if (el.closest(SKIP) || el.classList.contains("pcx-btn") || el.closest(".pcx-btn")) return;
69    const big = el.offsetWidth > 600 && el.offsetHeight > 240;
70    if (isAccentWash(getComputedStyle(el))) {
71      el.style.setProperty("background-image", big ? SOFT_GLOW : "none", "important");
72    }
73    // Pseudo-element glows can't take inline styles; flag them for legacy.css.
74    for (const pseudo of ["before", "after"]) {
75      if (isAccentWash(getComputedStyle(el, `::${pseudo}`))) {
76        el.classList.add(`pcx-soft-${pseudo}`, big ? "pcx-soft-big" : "pcx-soft-small");
77      }
78    }
79  };
80
81  // Same hue rule as src/lib/legacy-restyle.ts, for colours that only exist at
82  // runtime (third-party embeds such as OptinMonster inject their own styles).
83  const lilacFor = (c) => {
84    if (!c || c.a < 0.05) return null;
85    const r = c.r / 255, g = c.g / 255, b = c.b / 255;
86    const max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min;
87    if (d === 0) return null;
88    const sat = d / (1 - Math.abs(2 * l - 1));
89    let h = max === r ? ((g - b) / d) % 6 : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
90    h = (h * 60 + 360) % 360;
91    if (h < 250 || h > 300 || sat < 0.45 || l < 0.12 || l > 0.88) return null;
92    const hex = l >= 0.68 ? "#e39ff6" : l >= 0.4 ? "#b876d1" : l >= 0.25 ? "#8e56a0" : "#53335e";
93    const n = parseInt(hex.slice(1), 16);
94    if ((n >> 16) === c.r && ((n >> 8) & 255) === c.g && (n & 255) === c.b) return null;
95    return hex;
96  };
97  const fixViolet = (el) => {
98    if (el.closest(SKIP)) return;
99    const cs = getComputedStyle(el);
100    const bg = rgba(cs.backgroundColor);
101    const bgTo = lilacFor(bg);
102    if (bgTo) {
103      el.style.setProperty("background-color", bgTo, "important");
104      const fg = rgba(cs.color);
105      if (fg && lum(fg) > 0.8) el.style.setProperty("color", "#131313", "important");
106    }
107    const fgTo = lilacFor(rgba(cs.color));
108    if (fgTo && !bgTo) el.style.setProperty("color", fgTo === "#b876d1" ? "#e39ff6" : fgTo, "important");
109    const bdTo = lilacFor(rgba(cs.borderTopColor));
110    if (bdTo && parseFloat(cs.borderTopWidth) > 0) el.style.setProperty("border-color", "rgba(227, 159, 246, 0.35)", "important");
111  };
112
113  // Dark text left sitting on a dark surface (old white widgets restyled dark by
114  // CSS) gets the light text colour.
115  const surfaceOf = (el) => {
116    for (let n = el; n && n !== document.documentElement; n = n.parentElement) {
117      const c = rgba(getComputedStyle(n).backgroundColor);
118      if (c && c.a > 0.5) return c;
119    }
120    return { r: 19, g: 19, b: 19, a: 1 };
121  };
122  const hasOwnText = (el) => [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());
123  const fixContrast = (el) => {
124    if (el.closest(SKIP) || !hasOwnText(el)) return;
125    const c = rgba(getComputedStyle(el).color);
126    if (!c || lum(c) >= 0.4) return;
127    if (lum(surfaceOf(el)) < 0.3) el.style.setProperty("color", "#e5e1f0", "important");
128  };
129
130  const run = (root) => {
131    if (root.nodeType !== 1) return;
132    fixViolet(root);
133    root.querySelectorAll("*").forEach(fixViolet);
134    if (root.matches(BTN)) classifyButton(root);
135    root.querySelectorAll(BTN).forEach(classifyButton);
136    if (root.matches(CARD_TAGS)) flipCard(root);
137    root.querySelectorAll(CARD_TAGS).forEach(flipCard);
138    if (root.matches(CARD_TAGS)) softenGlow(root);
139    root.querySelectorAll(CARD_TAGS).forEach(softenGlow);
140    fixContrast(root);
141    root.querySelectorAll("*").forEach(fixContrast);
142  };
143
144  run(body);
145  window.addEventListener("load", () => run(body), { once: true });
146
147  let pending = [];
148  let timer = 0;
149  new MutationObserver((muts) => {
150    for (const m of muts) m.addedNodes.forEach((n) => n.nodeType === 1 && pending.push(n));
151    clearTimeout(timer);
152    timer = setTimeout(() => {
153      const nodes = pending;
154      pending = [];
155      nodes.forEach((n) => n.isConnected && run(n));
156    }, 150);
157  }).observe(body, { childList: true, subtree: true });
158})();

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.