Versión inicial del plugin FP Genocide Maps (v1.5.2)

CPT geep_map + shortcode [geep_maps] para la sección Architecture of
Genocide de la home: acordeón exclusivo con imagen por mapa, lightbox
con botón de compartir y enlaces #map-<slug>. Soporte WPML (EN/AR) con
herencia de la imagen del idioma original y CSS RTL.
This commit is contained in:
Ana
2026-07-17 12:19:41 +02:00
commit aed764c130
6 changed files with 1003 additions and 0 deletions
+262
View File
@@ -0,0 +1,262 @@
/*
* FP Genocide Maps — front-end styles.
*
* Replicates 1:1 the CSS Divi 5 generated for the original "texto mapa" row
* (row_3 / column_5 / column_6 / image_2 / toggle_0..7 on page 1834), so the
* section looks identical to the hand-built Divi version it replaces.
* Color/radius values reference the site's Divi global variables with their
* current values as fallbacks.
*/
/* --- Layout: replicates row_3's two flex columns (14/24 + 2/5, 2% gap). --- */
.geep-maps {
display: flex;
column-gap: 2%;
row-gap: 10px;
flex-wrap: nowrap;
}
.geep-maps-col-map {
width: calc(58.3333% - 2% * 0.41667); /* .et_flex_column_14_24 with 2% gap */
}
.geep-maps-col-toggles {
width: calc(40% - 2% * 0.6); /* .et_flex_column_2_5 with 2% gap */
display: flex;
flex-direction: column;
row-gap: 15px;
padding-left: 10px; /* column_6 */
min-width: 0;
}
@media only screen and (max-width: 767px) {
.geep-maps {
flex-wrap: wrap;
}
.geep-maps-col-map,
.geep-maps-col-toggles {
width: 100%;
}
}
/* --- Map image: replicates the Divi image module (image_2). --- */
.geep-maps-image {
display: flex;
line-height: 0;
}
.geep-maps-image-wrap {
display: inline-block;
position: relative;
max-width: 100%;
overflow: hidden;
border-radius: var(--gvid-4up6riitl2, 40px);
}
.geep-map-img {
position: relative;
max-width: 100%;
height: auto;
display: none;
opacity: 0;
transition: opacity 0.3s ease;
}
.geep-map-img.is-active {
display: block;
}
.geep-map-img.is-active.is-shown {
opacity: 1;
}
/* --- Toggles: replicates the 8 Divi toggle modules (toggle_0..7). --- */
.geep-toggle {
background-color: var(--gcid-primary-color, #d96c5d);
padding: 10px 2px 0 5px;
border: 0 solid #333;
word-wrap: break-word;
}
.geep-toggle.geep-toggle--first {
padding: 0 2px 2px 5px; /* toggle_0 had slightly different padding */
}
.geep-toggle-title {
cursor: pointer;
position: relative;
padding: 0 0 0 40px;
word-wrap: break-word;
/* Same line spacing as the intro paragraph above the section. */
line-height: var(--gvid-pfs7jbw9ep, 1.4em);
}
.geep-toggle--close .geep-toggle-title {
color: var(--gcid-mpn8tovm4t, #fff5f0) !important;
}
.geep-toggle--open .geep-toggle-title {
color: var(--gcid-heading-color, #424242) !important;
}
/*
* Checkbox-style marker: identical size and position in both states so
* nothing shifts when a map is selected; the open one is filled white.
*/
.geep-toggle-title::before {
content: "";
box-sizing: border-box;
position: absolute;
top: 50%;
margin-top: -9px;
left: 0;
right: auto;
width: 18px;
height: 18px;
border: 2px solid var(--gcid-secondary-color, #ffffff);
border-radius: 4px;
background: transparent;
}
.geep-toggle--open .geep-toggle-title::before {
background: var(--gcid-secondary-color, #ffffff);
}
.geep-toggle-content {
position: relative;
padding-top: 20px;
/* Align the excerpt with the title text (which sits after the marker). */
padding-left: 40px;
color: var(--gcid-secondary-color, #ffffff);
word-wrap: break-word;
overflow: hidden;
}
.geep-toggle--close .geep-toggle-content {
display: none;
}
/* Keep content visible while the open/close animation is running. */
.geep-toggle .geep-toggle-content.geep-animating {
display: block;
}
.geep-toggle-content p:last-of-type {
padding-bottom: 0;
}
/* --- RTL (Arabic): mirror icon and paddings. --- */
.rtl .geep-maps-col-toggles {
padding-left: 0;
padding-right: 10px;
}
.rtl .geep-toggle-title {
padding: 0 40px 0 0;
}
.rtl .geep-toggle-title::before {
left: auto;
right: 0;
}
.rtl .geep-toggle-content {
padding-left: 0;
padding-right: 40px;
}
/* --- Lightbox: click the map to view it larger + share its URL. --- */
.geep-maps-image-wrap {
cursor: zoom-in;
}
.geep-lightbox {
position: fixed;
inset: 0;
z-index: 999999;
display: none;
align-items: center;
justify-content: center;
padding: 3vh 3vw;
}
.geep-lightbox.is-open {
display: flex;
}
.geep-lightbox-noscroll,
.geep-lightbox-noscroll body {
overflow: hidden;
}
.geep-lightbox-backdrop {
position: absolute;
inset: 0;
background: rgba(20, 20, 20, 0.85);
cursor: zoom-out;
}
.geep-lightbox-inner {
position: relative;
margin: 0;
max-width: 94vw;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 12px;
line-height: 0;
}
.geep-lightbox-img {
max-width: 100%;
max-height: calc(94vh - 60px);
width: auto;
height: auto;
border-radius: 24px;
}
.geep-lightbox-actions {
display: flex;
gap: 10px;
line-height: 1;
}
.geep-lightbox-btn {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--gcid-mpn8tovm4t, #fff5f0);
color: var(--gcid-heading-color, #424242);
border: 0;
border-radius: 40px;
padding: 10px 18px;
font-size: 14px;
font-weight: 600;
line-height: 1;
cursor: pointer;
transition: background 0.2s ease;
}
.geep-lightbox-btn:hover {
background: var(--gcid-secondary-color, #ffffff);
}
.geep-lightbox-close {
padding: 10px 14px;
font-size: 18px;
}
.geep-lightbox-toast {
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
background: var(--gcid-heading-color, #424242);
color: var(--gcid-secondary-color, #ffffff);
border-radius: 40px;
padding: 10px 20px;
font-size: 14px;
line-height: 1;
white-space: nowrap;
}
+317
View File
@@ -0,0 +1,317 @@
/**
* FP Genocide Maps — front-end behavior.
*
* - Exclusive accordion with one map always open (700 ms slide, Divi's
* default speed); opening a map swaps the image with a fade.
* - Clicking the map image opens it in a lightbox with a share button.
* - Each map has a shareable URL (#map-<slug>): visiting it opens that map
* and scrolls the section into view.
*/
(function () {
'use strict';
var DURATION = 700;
var HASH_PREFIX = '#map-';
function slideDown(el) {
el.classList.add('geep-animating');
el.style.overflow = 'hidden';
el.style.height = '0px';
var target = el.scrollHeight;
el.style.transition = 'height ' + DURATION + 'ms ease-in-out';
requestAnimationFrame(function () {
el.style.height = target + 'px';
});
window.setTimeout(function () {
el.style.transition = '';
el.style.height = '';
el.style.overflow = '';
el.classList.remove('geep-animating');
}, DURATION);
}
function slideUp(el, done) {
el.classList.add('geep-animating');
el.style.overflow = 'hidden';
el.style.height = el.scrollHeight + 'px';
el.style.transition = 'height ' + DURATION + 'ms ease-in-out';
requestAnimationFrame(function () {
el.style.height = '0px';
});
window.setTimeout(function () {
el.style.transition = '';
el.style.height = '';
el.style.overflow = '';
el.classList.remove('geep-animating');
done();
}, DURATION);
}
function init(root) {
var labels;
try {
labels = JSON.parse(root.getAttribute('data-labels') || '{}');
} catch (e) {
labels = {};
}
var images = root.querySelectorAll('.geep-map-img');
// The first map is rendered open by the shortcode.
var current = root.querySelector('.geep-toggle--open');
function showMap(key) {
// No fallback: a map without its own image leaves the gap empty.
var target = null;
if (key) {
images.forEach(function (img) {
if (img.getAttribute('data-map') === key) {
target = img;
}
});
}
images.forEach(function (img) {
if (img !== target) {
img.classList.remove('is-active', 'is-shown');
}
});
if (target && !target.classList.contains('is-active')) {
target.classList.add('is-active');
requestAnimationFrame(function () {
requestAnimationFrame(function () {
target.classList.add('is-shown');
});
});
}
}
function close(toggle) {
var content = toggle.querySelector('.geep-toggle-content');
toggle.classList.remove('geep-toggle--open');
slideUp(content, function () {
toggle.classList.add('geep-toggle--close');
});
}
function open(toggle) {
var content = toggle.querySelector('.geep-toggle-content');
toggle.classList.remove('geep-toggle--close');
toggle.classList.add('geep-toggle--open');
slideDown(content);
}
function select(toggle) {
if (toggle === current) {
return;
}
if (current) {
close(current);
}
open(toggle);
current = toggle;
showMap(toggle.getAttribute('data-map'));
}
root.querySelectorAll('.geep-toggle').forEach(function (toggle) {
var title = toggle.querySelector('.geep-toggle-title');
var content = toggle.querySelector('.geep-toggle-content');
if (!title || !content) {
return;
}
title.addEventListener('click', function () {
if (content.classList.contains('geep-animating')) {
return;
}
select(toggle);
});
});
/* ------------------------------------------------------------------
* Shareable URLs: #map-<slug> selects that map on page load.
* ---------------------------------------------------------------- */
function shareUrl() {
var base = window.location.href.split('#')[0];
if (!current) {
return base;
}
return base + HASH_PREFIX + encodeURIComponent(current.getAttribute('data-slug'));
}
function openFromHash() {
if (window.location.hash.indexOf(HASH_PREFIX) !== 0) {
return;
}
var slug = decodeURIComponent(window.location.hash.slice(HASH_PREFIX.length));
var target = null;
root.querySelectorAll('.geep-toggle').forEach(function (t) {
if (t.getAttribute('data-slug') === slug) {
target = t;
}
});
if (!target || target === current) {
if (target) {
root.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
return;
}
// Switch instantly (no slide) — the page is just loading.
if (current) {
current.classList.remove('geep-toggle--open');
current.classList.add('geep-toggle--close');
}
target.classList.remove('geep-toggle--close');
target.classList.add('geep-toggle--open');
current = target;
showMap(target.getAttribute('data-map'));
root.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
openFromHash();
window.addEventListener('hashchange', openFromHash);
/* ------------------------------------------------------------------
* Lightbox with share button.
* ---------------------------------------------------------------- */
var lightbox = null;
var toastTimer = null;
function buildLightbox() {
var lb = document.createElement('div');
lb.className = 'geep-lightbox';
lb.setAttribute('role', 'dialog');
lb.setAttribute('aria-modal', 'true');
lb.innerHTML =
'<div class="geep-lightbox-backdrop"></div>' +
'<figure class="geep-lightbox-inner">' +
'<div class="geep-lightbox-actions">' +
'<button type="button" class="geep-lightbox-btn geep-lightbox-share">' +
'<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.6" y1="10.6" x2="15.4" y2="6.4"/><line x1="8.6" y1="13.4" x2="15.4" y2="17.6"/></svg>' +
'<span>' + (labels.share || 'Share map') + '</span>' +
'</button>' +
'<button type="button" class="geep-lightbox-btn geep-lightbox-close" aria-label="' + (labels.close || 'Close') + '">&#215;</button>' +
'</div>' +
'<img class="geep-lightbox-img" alt="">' +
'<div class="geep-lightbox-toast" hidden>' + (labels.copied || 'Link copied!') + '</div>' +
'</figure>';
document.body.appendChild(lb);
lb.querySelector('.geep-lightbox-backdrop').addEventListener('click', closeLightbox);
lb.querySelector('.geep-lightbox-close').addEventListener('click', closeLightbox);
lb.querySelector('.geep-lightbox-share').addEventListener('click', share);
return lb;
}
function openLightbox() {
var active = root.querySelector('.geep-map-img.is-active');
if (!active) {
return;
}
if (!lightbox) {
lightbox = buildLightbox();
}
var img = lightbox.querySelector('.geep-lightbox-img');
var key = active.getAttribute('data-map');
var full = active.src; // src attribute holds the full-size file.
// Show instantly whatever variant the page already downloaded for
// this map (it is in cache), instead of leaving the previous map
// on screen while the big file downloads.
img.dataset.map = key;
img.src = active.currentSrc || full;
img.alt = current ? current.querySelector('.geep-toggle-title').textContent : '';
// Then upgrade to the full-size file in the background.
if (img.src !== full) {
var pre = new Image();
pre.onload = function () {
// Only swap if the lightbox still shows this same map.
if (lightbox.classList.contains('is-open') && img.dataset.map === key) {
img.src = full;
}
};
pre.src = full;
}
lightbox.classList.add('is-open');
document.documentElement.classList.add('geep-lightbox-noscroll');
document.addEventListener('keydown', onKeydown);
}
function closeLightbox() {
if (!lightbox) {
return;
}
lightbox.classList.remove('is-open');
document.documentElement.classList.remove('geep-lightbox-noscroll');
document.removeEventListener('keydown', onKeydown);
}
function onKeydown(e) {
if (e.key === 'Escape') {
closeLightbox();
}
}
function toast() {
var t = lightbox.querySelector('.geep-lightbox-toast');
t.hidden = false;
window.clearTimeout(toastTimer);
toastTimer = window.setTimeout(function () {
t.hidden = true;
}, 2200);
}
function share() {
var url = shareUrl();
var title = current ? current.querySelector('.geep-toggle-title').textContent : document.title;
if (navigator.share) {
navigator.share({ title: title, url: url }).catch(function () {});
return;
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(url).then(toast, function () {
fallbackCopy(url);
});
} else {
fallbackCopy(url);
}
}
function fallbackCopy(url) {
var ta = document.createElement('textarea');
ta.value = url;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
try {
document.execCommand('copy');
toast();
} catch (e) {}
document.body.removeChild(ta);
}
var wrap = root.querySelector('.geep-maps-image-wrap');
if (wrap) {
wrap.addEventListener('click', openLightbox);
wrap.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
openLightbox();
}
});
}
}
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
ready(function () {
document.querySelectorAll('.geep-maps').forEach(init);
});
})();