Update from Git Manager GUI

This commit is contained in:
2026-03-18 21:56:43 +01:00
parent b7badfc59d
commit ea210d5a75
4 changed files with 552 additions and 0 deletions

46
assets/css/admin.css Normal file
View File

@@ -0,0 +1,46 @@
/* ===== WP Multi Wiki Admin CSS ======================================== */
.wmw-admin-wrap { max-width: 1200px; }
.wmw-admin-wrap h1 .dashicons { vertical-align: middle; margin-right: .3rem; color: #0073aa; }
/* ── Wiki Cards Grid (Overview) ─────────────────────────────────────────── */
.wmw-wiki-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1.25rem;
margin: 1.5rem 0;
}
.wmw-wiki-card {
background: #fff;
border: 1px solid #dcdcde;
border-radius: 6px;
padding: 1.25rem;
box-shadow: 0 1px 4px rgba(0,0,0,.05);
}
.wmw-wiki-card-header { display: flex; align-items: center; gap: .75rem; margin-bottom: .75rem; }
.wmw-wiki-card-header .dashicons { font-size: 2rem; width: 2rem; height: 2rem; }
.wmw-wiki-card-header .wmw-wiki-icon-img { width: 36px; height: 36px; object-fit: contain; }
.wmw-wiki-card-header h3 { margin: 0; font-size: 1rem; }
.wmw-wiki-card-meta { display: flex; gap: .5rem; align-items: center; font-size: .82rem; color: #646970; margin-bottom: .75rem; }
.wmw-version-badge { background: #0073aa; color: #fff; padding: .1rem .45rem; border-radius: 20px; font-size: .75rem; }
.wmw-wiki-card-actions { display: flex; gap: .4rem; flex-wrap: wrap; }
/* ── Empty State ─────────────────────────────────────────────────────────── */
.wmw-empty-state {
text-align: center;
padding: 3rem 2rem;
background: #f9f9f9;
border: 2px dashed #dcdcde;
border-radius: 8px;
margin: 1.5rem 0;
}
.wmw-empty-state .dashicons { font-size: 4rem; width: 4rem; height: 4rem; color: #b0b5bd; }
.wmw-empty-state h2 { margin: .75rem 0 .5rem; color: #646970; }
.wmw-empty-state p { color: #8c8f94; margin-bottom: 1.25rem; }
/* ── Stats Bar ───────────────────────────────────────────────────────────── */
.wmw-stats-bar { background: #fff; border: 1px solid #dcdcde; border-radius: 6px; padding: 1.25rem; margin-top: 1.5rem; }
.wmw-stats-bar h2 { margin: 0 0 1rem; font-size: 1rem; }
.wmw-stats-grid { display: flex; gap: 2rem; flex-wrap: wrap; }
.wmw-stat { display: flex; flex-direction: column; align-items: center; min-width: 80px; }
.wmw-stat-number { font-size: 2rem; font-weight: 700; color: #0073aa; line-height: 1; }
.wmw-stat-label { font-size: .8rem; color: #646970; margin-top: .25rem; }

317
assets/css/frontend.css Normal file
View File

@@ -0,0 +1,317 @@
/* ===== WP Multi Wiki Frontend CSS ===================================== */
:root {
--wmw-color: #0073aa;
--wmw-radius: 8px;
--wmw-shadow: 0 2px 12px rgba(0,0,0,.08);
--wmw-trans: .2s ease;
--wmw-bg: #fff;
--wmw-border: #e5e7eb;
--wmw-text: #1f2937;
--wmw-muted: #6b7280;
--wmw-sidebar-w: 280px;
}
/* ──── All Wikis Grid ────────────────────────────────────────────────────── */
.wmw-wikis-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin-top: 1.5rem;
}
.wmw-wiki-card {
display: flex;
flex-direction: column;
background: var(--wmw-bg);
border: 1px solid var(--wmw-border);
border-top: 4px solid var(--wmw-color);
border-radius: var(--wmw-radius);
padding: 1.5rem;
text-decoration: none;
color: var(--wmw-text);
box-shadow: var(--wmw-shadow);
transition: transform var(--wmw-trans), box-shadow var(--wmw-trans);
}
.wmw-wiki-card:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0,0,0,.12);
text-decoration: none;
color: var(--wmw-text);
}
.wmw-wiki-card-icon { margin-bottom: .75rem; }
.wmw-wiki-card-icon .dashicons { font-size: 2.5rem; width: 2.5rem; height: 2.5rem; color: var(--wmw-color); }
.wmw-wiki-card-icon img { width: 48px; height: 48px; object-fit: contain; }
.wmw-wiki-card-body h3 { margin: 0 0 .4rem; font-size: 1.1rem; }
.wmw-wiki-card-body p { margin: 0 0 .75rem; color: var(--wmw-muted); font-size: .9rem; line-height: 1.5; }
.wmw-wiki-card-footer {
display: flex;
gap: .5rem;
align-items: center;
margin-top: auto;
padding-top: .75rem;
border-top: 1px solid var(--wmw-border);
font-size: .8rem;
}
.wmw-article-count { color: var(--wmw-muted); }
.wmw-version {
background: var(--wmw-color);
color: #fff;
padding: .1rem .5rem;
border-radius: 20px;
font-size: .75rem;
}
/* ──── TOC ───────────────────────────────────────────────────────────────── */
.wmw-toc {
background: #f9fafb;
border: 1px solid var(--wmw-border);
border-left: 4px solid var(--wmw-color);
border-radius: var(--wmw-radius);
padding: 1rem 1.25rem;
margin: 0 0 2rem;
max-width: 600px;
}
.wmw-toc-header { display: flex; align-items: center; gap: .5rem; margin-bottom: .75rem; }
.wmw-toc-header strong { flex: 1; }
.wmw-toc-toggle { background: none; border: none; cursor: pointer; padding: 0; color: var(--wmw-muted); }
.wmw-toc-list { margin: 0; padding-left: 1.25rem; list-style: decimal; }
.wmw-toc-sublist { margin: .25rem 0; padding-left: 1.25rem; list-style: lower-alpha; }
.wmw-toc-list li { margin: .2rem 0; }
.wmw-toc-list a { color: var(--wmw-text); text-decoration: none; font-size: .9rem; transition: color var(--wmw-trans); }
.wmw-toc-list a:hover { color: var(--wmw-color); text-decoration: underline; }
.wmw-toc-list a.wmw-toc-active { color: var(--wmw-color); font-weight: 600; }
/* ──── Article Layout ────────────────────────────────────────────────────── */
.wmw-article-layout { display: flex; gap: 2rem; align-items: flex-start; max-width: 1200px; margin: 0 auto; }
/* ──── Sidebar ───────────────────────────────────────────────────────────── */
.wmw-sidebar {
width: var(--wmw-sidebar-w);
flex-shrink: 0;
position: sticky;
top: 2rem;
max-height: calc(100vh - 4rem);
overflow-y: auto;
background: #f9fafb;
border: 1px solid var(--wmw-border);
border-top: 3px solid var(--wmw-color);
border-radius: var(--wmw-radius);
padding: 1rem;
scrollbar-width: thin;
}
.wmw-sidebar-header { margin-bottom: .75rem; padding-bottom: .75rem; border-bottom: 1px solid var(--wmw-border); }
.wmw-sidebar-wiki-link {
display: flex;
align-items: center;
gap: .25rem;
color: var(--wmw-color);
font-weight: 600;
text-decoration: none;
font-size: .9rem;
}
.wmw-sidebar-wiki-link:hover { text-decoration: underline; }
.wmw-sidebar-search { margin-bottom: .75rem; }
.wmw-sidebar .wmw-section { margin-bottom: .75rem; }
.wmw-sidebar .wmw-section-title {
font-size: .75rem;
text-transform: uppercase;
letter-spacing: .05em;
color: var(--wmw-muted);
margin: 0 0 .3rem;
display: flex;
align-items: center;
gap: .25rem;
}
.wmw-sidebar .wmw-article-list { list-style: none; margin: 0; padding: 0; }
.wmw-sidebar .wmw-article-list li { margin: .1rem 0; }
.wmw-sidebar .wmw-article-list a {
display: flex;
align-items: center;
gap: .3rem;
padding: .3rem .5rem;
border-radius: 4px;
color: var(--wmw-text);
text-decoration: none;
font-size: .875rem;
transition: background var(--wmw-trans), color var(--wmw-trans);
}
.wmw-sidebar .wmw-article-list a:hover,
.wmw-sidebar .wmw-article-list a.wmw-current { background: var(--wmw-color); color: #fff; }
/* ──── Article Content ───────────────────────────────────────────────────── */
.wmw-article-content { flex: 1; min-width: 0; }
.wmw-article-header { margin-bottom: 1.5rem; border-bottom: 1px solid var(--wmw-border); padding-bottom: 1rem; }
.wmw-article-header h1 { margin: 0 0 .5rem; }
.wmw-article-meta { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.wmw-updated { font-size: .85rem; color: var(--wmw-muted); }
.wmw-tags { display: flex; flex-wrap: wrap; gap: .35rem; }
.wmw-tag {
background: #e0f0fb;
color: var(--wmw-color);
padding: .15rem .5rem;
border-radius: 20px;
font-size: .78rem;
text-decoration: none;
transition: background var(--wmw-trans);
}
.wmw-tag:hover { background: var(--wmw-color); color: #fff; }
/* ──── Breadcrumb ────────────────────────────────────────────────────────── */
.wmw-breadcrumb {
font-size: .85rem;
color: var(--wmw-muted);
margin-bottom: 1rem;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: .25rem;
}
.wmw-breadcrumb a { color: var(--wmw-color); text-decoration: none; }
.wmw-breadcrumb a:hover { text-decoration: underline; }
/* ──── Prev / Next Nav ───────────────────────────────────────────────────── */
.wmw-article-nav {
display: flex;
justify-content: space-between;
gap: 1rem;
margin-top: 2.5rem;
padding-top: 1.5rem;
border-top: 1px solid var(--wmw-border);
}
.wmw-nav-prev, .wmw-nav-next {
display: flex;
align-items: center;
gap: .5rem;
padding: .75rem 1rem;
border: 1px solid var(--wmw-border);
border-radius: var(--wmw-radius);
text-decoration: none;
color: var(--wmw-text);
max-width: 48%;
transition: border-color var(--wmw-trans), box-shadow var(--wmw-trans);
}
.wmw-nav-prev:hover, .wmw-nav-next:hover { border-color: var(--wmw-color); box-shadow: var(--wmw-shadow); text-decoration: none; color: var(--wmw-text); }
.wmw-nav-next { margin-left: auto; text-align: right; }
.wmw-nav-prev span, .wmw-nav-next span { display: flex; flex-direction: column; }
.wmw-nav-prev em, .wmw-nav-next em { font-style: normal; font-size: .75rem; color: var(--wmw-muted); }
.wmw-nav-prev .dashicons, .wmw-nav-next .dashicons { color: var(--wmw-color); flex-shrink: 0; }
/* ──── Wiki Header (single wiki page) ───────────────────────────────────── */
.wmw-wiki-header {
display: flex;
align-items: flex-start;
gap: 1.25rem;
margin-bottom: 2rem;
padding: 1.5rem;
background: #f9fafb;
border-radius: var(--wmw-radius);
border-left: 4px solid var(--wmw-color);
}
.wmw-wiki-header-icon .dashicons { font-size: 3rem; width: 3rem; height: 3rem; color: var(--wmw-color); }
.wmw-wiki-header-icon img { width: 64px; height: 64px; object-fit: contain; }
.wmw-wiki-title { margin: 0 0 .35rem !important; }
.wmw-version-badge {
display: inline-block;
background: var(--wmw-color);
color: #fff;
padding: .15rem .6rem;
border-radius: 20px;
font-size: .8rem;
margin-bottom: .5rem;
}
.wmw-wiki-description { margin: .5rem 0 0; color: var(--wmw-muted); }
/* ──── Sections grid (wiki overview) ────────────────────────────────────── */
.wmw-wiki-wrap .wmw-section { margin-bottom: 1.5rem; }
.wmw-wiki-wrap .wmw-section-title {
font-size: 1rem;
font-weight: 700;
color: var(--wmw-color);
border-bottom: 2px solid var(--wmw-color);
padding-bottom: .4rem;
margin-bottom: .75rem;
display: flex;
align-items: center;
gap: .4rem;
}
.wmw-wiki-wrap .wmw-article-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: .4rem;
}
.wmw-wiki-wrap .wmw-article-list a {
display: flex;
align-items: center;
gap: .5rem;
padding: .5rem .75rem;
border-radius: 6px;
background: #f9fafb;
border: 1px solid var(--wmw-border);
color: var(--wmw-text);
text-decoration: none;
font-size: .9rem;
transition: background var(--wmw-trans), border-color var(--wmw-trans), color var(--wmw-trans);
}
.wmw-wiki-wrap .wmw-article-list a:hover { background: var(--wmw-color); color: #fff; border-color: var(--wmw-color); }
/* ──── Search Widget ─────────────────────────────────────────────────────── */
.wmw-search-widget { position: relative; }
.wmw-search-input-wrap {
display: flex;
align-items: center;
background: #fff;
border: 1px solid var(--wmw-border);
border-radius: 6px;
padding: .4rem .75rem;
gap: .4rem;
transition: border-color var(--wmw-trans), box-shadow var(--wmw-trans);
}
.wmw-search-input-wrap:focus-within { border-color: var(--wmw-color); box-shadow: 0 0 0 3px rgba(0,115,170,.15); }
.wmw-search-icon { color: var(--wmw-muted); font-size: 1rem; width: 1rem; height: 1rem; }
.wmw-search-input { flex: 1; border: none; outline: none; font-size: .875rem; background: transparent; color: var(--wmw-text); }
.wmw-search-clear { background: none; border: none; cursor: pointer; color: var(--wmw-muted); padding: 0; }
.wmw-search-results {
position: absolute;
top: calc(100% + 4px);
left: 0; right: 0;
background: #fff;
border: 1px solid var(--wmw-border);
border-radius: var(--wmw-radius);
box-shadow: var(--wmw-shadow);
max-height: 360px;
overflow-y: auto;
z-index: 999;
display: none;
}
.wmw-search-results.wmw-open { display: block; }
.wmw-search-result-item {
display: block;
padding: .75rem 1rem;
border-bottom: 1px solid var(--wmw-border);
text-decoration: none;
color: var(--wmw-text);
transition: background var(--wmw-trans);
}
.wmw-search-result-item:last-child { border-bottom: none; }
.wmw-search-result-item:hover { background: #f0f9ff; text-decoration: none; }
.wmw-search-result-title { font-weight: 600; font-size: .9rem; }
.wmw-search-result-meta { font-size: .75rem; color: var(--wmw-muted); margin: .15rem 0; }
.wmw-search-result-excerpt { font-size: .8rem; color: var(--wmw-muted); line-height: 1.4; }
.wmw-search-result-excerpt mark { background: #fef08a; padding: 0 2px; border-radius: 2px; }
.wmw-search-no-results { padding: 1rem; text-align: center; color: var(--wmw-muted); font-size: .9rem; }
/* ──── Responsive ────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
.wmw-article-layout { flex-direction: column; }
.wmw-sidebar { width: 100%; position: static; max-height: none; }
.wmw-nav-prev, .wmw-nav-next { max-width: 100%; }
.wmw-article-nav { flex-direction: column; }
.wmw-nav-next { margin-left: 0; }
}
@media (max-width: 600px) {
.wmw-wikis-grid { grid-template-columns: 1fr; }
.wmw-wiki-header { flex-direction: column; }
.wmw-wiki-wrap .wmw-article-list { grid-template-columns: 1fr; }
}

109
assets/js/search.js Normal file
View File

@@ -0,0 +1,109 @@
/**
* WP Multi Wiki AJAX Search Script
*/
(function ($) {
'use strict';
$(document).ready(function () {
$('.wmw-search-widget').each(function () {
var $widget = $(this);
var $input = $widget.find('.wmw-search-input');
var $results = $widget.find('.wmw-search-results');
var $clear = $widget.find('.wmw-search-clear');
var wikiId = parseInt($widget.data('wiki-id'), 10) || 0;
var timer = null;
// ── Input handler ─────────────────────────────────────────────────
$input.on('input', function () {
clearTimeout(timer);
var term = $input.val().trim();
if (term.length < 2) {
closeResults();
$clear.hide();
return;
}
$clear.show();
timer = setTimeout(function () {
doSearch(term);
}, 280);
});
// ── Clear button ──────────────────────────────────────────────────
$clear.on('click', function () {
$input.val('').trigger('input').focus();
});
// ── Close on outside click ────────────────────────────────────────
$(document).on('click.wmw', function (e) {
if (!$widget.is(e.target) && !$widget.has(e.target).length) {
closeResults();
}
});
// ── Keyboard: escape closes ───────────────────────────────────────
$input.on('keydown', function (e) {
if (e.key === 'Escape') closeResults();
});
function doSearch(term) {
$results.html('<div class="wmw-search-no-results">Suche...</div>').addClass('wmw-open');
$.ajax({
url: wmwData.ajaxUrl,
type: 'POST',
data: {
action: 'wmw_search',
nonce: wmwData.nonce,
term: term,
wiki_id: wikiId,
},
success: function (response) {
if (!response.success) {
$results.html('<div class="wmw-search-no-results">Fehler bei der Suche.</div>');
return;
}
var items = response.data;
if (!items.length) {
$results.html('<div class="wmw-search-no-results">Keine Ergebnisse fuer &ldquo;' + escHtml(term) + '&rdquo;</div>');
return;
}
var html = '';
items.forEach(function (item) {
html += '<a href="' + escAttr(item.url) + '" class="wmw-search-result-item">';
html += '<div class="wmw-search-result-title">' + escHtml(item.title) + '</div>';
if (item.wiki_title) {
html += '<div class="wmw-search-result-meta">' + escHtml(item.wiki_title) + '</div>';
}
if (item.excerpt) {
html += '<div class="wmw-search-result-excerpt">' + item.excerpt + '</div>';
}
html += '</a>';
});
$results.html(html).addClass('wmw-open');
},
error: function () {
$results.html('<div class="wmw-search-no-results">Verbindungsfehler.</div>');
},
});
}
function closeResults() {
$results.removeClass('wmw-open').html('');
}
});
// ── Helpers ───────────────────────────────────────────────────────────
function escHtml(str) {
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function escAttr(str) { return escHtml(str); }
});
})(jQuery);

80
assets/js/toc.js Normal file
View File

@@ -0,0 +1,80 @@
/**
* WP Multi Wiki TOC Script
* Highlights active TOC entry while scrolling + toggle functionality.
*/
(function () {
'use strict';
document.addEventListener('DOMContentLoaded', function () {
var toc = document.getElementById('wmw-toc');
if (!toc) return;
// ── Toggle ────────────────────────────────────────────────────────────
var toggleBtn = toc.querySelector('.wmw-toc-toggle');
var tocList = document.getElementById('wmw-toc-list');
if (toggleBtn && tocList) {
toggleBtn.addEventListener('click', function () {
var expanded = toggleBtn.getAttribute('aria-expanded') === 'true';
toggleBtn.setAttribute('aria-expanded', String(!expanded));
tocList.style.display = expanded ? 'none' : '';
var icon = toggleBtn.querySelector('.wmw-toc-toggle-icon');
if (icon) icon.innerHTML = expanded ? '&#9654;' : '&#9660;';
});
}
// ── Active Highlight on Scroll ────────────────────────────────────────
var links = toc.querySelectorAll('a[href^="#"]');
if (!links.length) return;
var headings = [];
links.forEach(function (link) {
var id = link.getAttribute('href').substring(1);
var el = document.getElementById(id);
if (el) headings.push({ el: el, link: link });
});
function setActive() {
var scrollY = window.scrollY || window.pageYOffset;
var offset = 80; // sticky header offset
var activeIdx = -1;
headings.forEach(function (h, i) {
if (h.el.getBoundingClientRect().top + scrollY - offset <= scrollY) {
activeIdx = i;
}
});
links.forEach(function (l) { l.classList.remove('wmw-toc-active'); });
if (activeIdx >= 0) {
headings[activeIdx].link.classList.add('wmw-toc-active');
}
}
var ticking = false;
window.addEventListener('scroll', function () {
if (!ticking) {
requestAnimationFrame(function () {
setActive();
ticking = false;
});
ticking = true;
}
}, { passive: true });
setActive(); // run once on load
// ── Sidebar: mark current article ────────────────────────────────────
var currentUrl = window.location.href.replace(/\/$/, '');
document.querySelectorAll('.wmw-sidebar .wmw-article-list a').forEach(function (a) {
if (a.href.replace(/\/$/, '') === currentUrl) {
a.classList.add('wmw-current');
// Scroll link into view inside sidebar
var sidebar = document.getElementById('wmw-sidebar');
if (sidebar) {
var linkTop = a.offsetTop;
sidebar.scrollTop = linkTop - 80;
}
}
});
});
})();