Modernize individual page, add dark mode fixes, and restyle gallery

- Redesign individual page header: photo beside name/year/age/username,
  pencil icon edit button, stacked vertical fact cards, iOS toggle,
  underline tabs, and responsive mobile layout
- Add global dark mode fixes for modals, forms, dropdowns (both
  data-theme=dark and prefers-color-scheme auto mode)
- Restyle colorbox gallery: blurred backdrop, centered image, no zoom
  animation, clean controls with drop-shadow
- Override family navigator with thumbnails linking to individual pages
  instead of raw images, matching full diagram gender colors
- Add high-contrast link colors and silhouette placeholder sizing
This commit is contained in:
2026-03-15 15:35:37 +01:00
parent fbdad56ef3
commit 02599e5876
4 changed files with 1289 additions and 0 deletions
+82
View File
@@ -59,6 +59,8 @@ class BockenTheme extends AbstractModule implements ModuleCustomInterface, Modul
}
$sheets[] = $this->assetUrl('css/fonts.css');
$sheets[] = $this->assetUrl('css/theme.css');
$sheets[] = $this->assetUrl('css/dark-fixes.css');
$sheets[] = $this->assetUrl('css/individual.css');
return $sheets;
}
@@ -306,6 +308,83 @@ class BockenTheme extends AbstractModule implements ModuleCustomInterface, Modul
}
}
// --- Reformat individual page header ---
function reformatIndividualHeader() {
if (!document.body.classList.contains('wt-route-IndividualPage')) return;
var h2 = document.querySelector('.wt-page-title');
if (!h2 || h2.dataset.reformatted) return;
h2.dataset.reformatted = '1';
// --- Reformat title text ---
var nameEl = h2.querySelector('.NAME');
if (!nameEl) return;
var name = nameEl.textContent.trim();
var fullText = h2.textContent;
var yearMatch = fullText.match(/,\s*(\d{4})[\-](\d{4})?/);
var yearPart = '';
if (yearMatch) {
yearPart = yearMatch[1] + '' + (yearMatch[2] || '');
}
// Match any parenthesized text containing a number (language-agnostic)
var ageMatch = fullText.match(/\([^)]*\d+[^)]*\)/);
var agePart = ageMatch ? ageMatch[0] : '';
var userLink = h2.querySelector('a');
var userHtml = '';
if (userLink) {
userHtml = userLink.outerHTML;
}
h2.innerHTML =
'<span class="bocken-title-name">' + name + '</span>' +
(yearPart || agePart ? '<span class="bocken-title-meta">' + yearPart + (agePart ? ' ' + agePart : '') + '</span>' : '') +
(userHtml ? '<span class="bocken-title-user">' + userHtml + '</span>' : '');
// --- Move photo into the title bar ---
var titleBar = h2.closest('.d-flex.mb-4');
var photoCol = document.querySelector('.wt-route-IndividualPage .row.mb-4 > .col-sm-3');
if (titleBar && photoCol) {
titleBar.classList.add('bocken-individual-header');
titleBar.insertBefore(photoCol, titleBar.firstChild);
}
// --- Replace edit button text with pencil icon ---
var editBtn = document.querySelector('.wt-page-menu-button');
if (editBtn) {
var iconSpan = editBtn.querySelector('.wt-icon-menu');
if (iconSpan) {
editBtn.innerHTML = '';
iconSpan.innerHTML = '<i data-lucide="pencil"></i>';
editBtn.appendChild(iconSpan);
if (typeof lucide !== 'undefined') {
lucide.createIcons({ nodes: [editBtn] });
}
}
}
}
// --- Fix colorbox: disable zoom animation ---
function fixColorbox() {
if (typeof jQuery !== 'undefined') {
var waitForColorbox = setInterval(function() {
if (jQuery.fn.colorbox) {
var origColorbox = jQuery.fn.colorbox;
jQuery.fn.colorbox = function(opts) {
opts = jQuery.extend({}, opts, { transition: 'none', speed: 0 });
return origColorbox.call(this, opts);
};
jQuery.fn.colorbox.settings = origColorbox.settings;
jQuery.colorbox = origColorbox;
clearInterval(waitForColorbox);
}
}, 50);
}
}
// --- Init ---
function init() {
injectLogo();
@@ -314,6 +393,8 @@ class BockenTheme extends AbstractModule implements ModuleCustomInterface, Modul
shortenLanguage();
injectPageSearch();
highlightActiveNav();
reformatIndividualHeader();
fixColorbox();
// Init all Lucide icons
if (typeof lucide !== 'undefined') {
@@ -346,5 +427,6 @@ class BockenTheme extends AbstractModule implements ModuleCustomInterface, Modul
View::registerCustomView('::lists/individuals-table', $this->name() . '::lists/individuals-table');
View::registerCustomView('::lists/families-table', $this->name() . '::lists/families-table');
View::registerCustomView('::individual-page-menu', $this->name() . '::individual-page-menu');
View::registerCustomView('::modules/family_nav/sidebar-family', $this->name() . '::modules/family_nav/sidebar-family');
}
}