diff --git a/assets/css/app.css b/assets/css/app.css
index cbee93a..2ed3cba 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -12,6 +12,10 @@ body {
overflow-y: auto;
}
+.content-area {
+ min-width: 0;
+}
+
.sidebar .nav-link {
padding: 0.6rem 1rem;
border-radius: 0.375rem;
@@ -54,7 +58,54 @@ body {
line-height: 1.7;
}
+.article-content,
+.article-content * {
+ overflow-wrap: anywhere;
+}
+
.btn-group .btn + form .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
+
+.bp-toast-container {
+ z-index: 2000;
+ max-width: 420px;
+}
+
+.bp-toast {
+ border-radius: 12px;
+}
+
+.bp-toast .toast-body {
+ font-size: 0.95rem;
+}
+
+.bp-toast.text-bg-warning .btn-close {
+ filter: none;
+}
+
+.bp-toast-fallback {
+ margin-bottom: 0.5rem;
+ padding: 0.75rem 0.95rem;
+ border-radius: 10px;
+ background: #1f2a44;
+ color: #fff;
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.25);
+}
+
+.bp-confirm-modal .modal-content {
+ border: 0;
+ border-radius: 14px;
+ box-shadow: 0 1rem 2rem rgba(19, 31, 56, 0.2);
+}
+
+.bp-confirm-modal .modal-title {
+ font-size: 1.1rem;
+ font-weight: 700;
+}
+
+.bp-confirm-modal .modal-body p {
+ color: #445066;
+ line-height: 1.5;
+}
diff --git a/assets/js/app.js b/assets/js/app.js
index 33f5a06..ac8caa3 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -1,76 +1,294 @@
// BackPRO - Frontend Scripts
+(function () {
+ 'use strict';
-document.addEventListener('DOMContentLoaded', function () {
+ var confirmQueue = Promise.resolve();
+ var confirmUi = null;
- // Test connection buttons
- document.querySelectorAll('.btn-test-connection').forEach(function (btn) {
- btn.addEventListener('click', function () {
- var siteId = this.dataset.siteId;
- var button = this;
- var originalHtml = button.innerHTML;
+ function getToastClass(type) {
+ if (type === 'success') return 'text-bg-success';
+ if (type === 'danger' || type === 'error') return 'text-bg-danger';
+ if (type === 'warning') return 'text-bg-warning';
+ return 'text-bg-primary';
+ }
- button.innerHTML = '';
- button.disabled = true;
+ function getToastTitle(type) {
+ if (type === 'success') return 'Sukces';
+ if (type === 'danger' || type === 'error') return 'Blad';
+ if (type === 'warning') return 'Uwaga';
+ return 'Informacja';
+ }
- fetch('/sites/' + siteId + '/test', { method: 'POST' })
- .then(function (r) { return r.json(); })
- .then(function (data) {
- if (data.success) {
- button.innerHTML = '';
- button.classList.remove('btn-outline-success');
- button.classList.add('btn-success');
- } else {
- button.innerHTML = '';
- button.classList.remove('btn-outline-success');
- button.classList.add('btn-danger');
- alert('Błąd połączenia: ' + data.message);
- }
- })
- .catch(function () {
- button.innerHTML = '';
- button.classList.add('btn-danger');
- alert('Błąd sieci');
- })
- .finally(function () {
- button.disabled = false;
- setTimeout(function () {
- button.innerHTML = originalHtml;
- button.className = button.className.replace('btn-success', 'btn-outline-success').replace('btn-danger', 'btn-outline-success');
- }, 3000);
- });
+ function ensureToastContainer() {
+ var container = document.getElementById('bpToastContainer');
+ if (container) return container;
+
+ container = document.createElement('div');
+ container.id = 'bpToastContainer';
+ container.className = 'toast-container position-fixed top-0 end-0 p-3 bp-toast-container';
+ document.body.appendChild(container);
+ return container;
+ }
+
+ function showToast(message, type, options) {
+ if (!message) return;
+
+ if (!window.bootstrap || !window.bootstrap.Toast) {
+ var fallbackContainer = ensureToastContainer();
+ var fallbackToast = document.createElement('div');
+ fallbackToast.className = 'bp-toast-fallback';
+ fallbackToast.textContent = message;
+ fallbackContainer.appendChild(fallbackToast);
+ setTimeout(function () {
+ fallbackToast.remove();
+ }, 4000);
+ return;
+ }
+
+ var opts = options || {};
+ var container = ensureToastContainer();
+ var toast = document.createElement('div');
+ var toastClass = getToastClass(type || 'info');
+ var title = opts.title || getToastTitle(type || 'info');
+ var delay = typeof opts.delay === 'number' ? opts.delay : 5000;
+
+ toast.className = 'toast border-0 shadow-sm bp-toast ' + toastClass;
+ toast.setAttribute('role', 'alert');
+ toast.setAttribute('aria-live', 'assertive');
+ toast.setAttribute('aria-atomic', 'true');
+ toast.innerHTML =
+ '
' +
+ '
' +
+ '' + title + ': ' + message +
+ '
' +
+ '
' +
+ '
';
+
+ container.appendChild(toast);
+ var bsToast = new bootstrap.Toast(toast, { delay: delay });
+ toast.addEventListener('hidden.bs.toast', function () {
+ toast.remove();
});
- });
+ bsToast.show();
+ }
- // Topic edit buttons
- document.querySelectorAll('.btn-edit-topic').forEach(function (btn) {
- btn.addEventListener('click', function () {
- var id = this.dataset.id;
- var form = document.getElementById('topicForm');
- var title = document.getElementById('topicFormTitle');
- var submit = document.getElementById('topicFormSubmit');
+ function ensureConfirmUi() {
+ if (confirmUi) return confirmUi;
- form.action = '/topics/' + id + '/update';
- title.textContent = 'Edytuj temat';
- submit.textContent = 'Zapisz zmiany';
+ var existing = document.getElementById('bpConfirmModal');
+ if (!existing) {
+ var modal = document.createElement('div');
+ modal.className = 'modal fade bp-confirm-modal';
+ modal.id = 'bpConfirmModal';
+ modal.tabIndex = -1;
+ modal.setAttribute('aria-hidden', 'true');
+ modal.innerHTML =
+ '' +
+ '
' +
+ '' +
+ '
' +
+ '' +
+ '
' +
+ '
';
+ document.body.appendChild(modal);
+ existing = modal;
+ }
- document.getElementById('topic_name').value = this.dataset.name;
- document.getElementById('topic_description').value = this.dataset.description;
- document.getElementById('topic_wp_category').value = this.dataset.wpCategory || '';
- document.getElementById('topic_is_active').checked = this.dataset.active === '1';
+ confirmUi = {
+ el: existing,
+ modal: window.bootstrap && window.bootstrap.Modal
+ ? new bootstrap.Modal(existing, { backdrop: 'static', keyboard: false })
+ : null,
+ titleEl: existing.querySelector('#bpConfirmTitle'),
+ messageEl: existing.querySelector('#bpConfirmMessage'),
+ cancelBtn: existing.querySelector('[data-role="cancel"]'),
+ confirmBtn: existing.querySelector('[data-role="confirm"]')
+ };
+ return confirmUi;
+ }
- var globalSelect = document.getElementById('topic_global_id');
- if (globalSelect) {
- globalSelect.value = this.dataset.globalTopic || '';
+ function showConfirmDialog(message, options) {
+ var opts = options || {};
+
+ if (!window.bootstrap || !window.bootstrap.Modal) {
+ showToast('Brak komponentu potwierdzenia. Operacja zostala wstrzymana.', 'warning');
+ return Promise.resolve(false);
+ }
+
+ var ui = ensureConfirmUi();
+ ui.titleEl.textContent = opts.title || 'Potwierdzenie';
+ ui.messageEl.textContent = message || 'Czy na pewno?';
+ ui.cancelBtn.textContent = opts.cancelText || 'Anuluj';
+ ui.confirmBtn.textContent = opts.confirmText || 'Potwierdz';
+ ui.confirmBtn.className = 'btn ' + (opts.confirmClass || 'btn-danger');
+
+ return new Promise(function (resolve) {
+ var confirmed = false;
+
+ function cleanup() {
+ ui.confirmBtn.removeEventListener('click', onConfirm);
+ ui.cancelBtn.removeEventListener('click', onCancel);
+ ui.el.removeEventListener('hidden.bs.modal', onHidden);
+ }
+
+ function onConfirm() {
+ confirmed = true;
+ ui.modal.hide();
+ }
+
+ function onCancel() {
+ ui.modal.hide();
+ }
+
+ function onHidden() {
+ cleanup();
+ resolve(confirmed);
+ }
+
+ ui.confirmBtn.addEventListener('click', onConfirm);
+ ui.cancelBtn.addEventListener('click', onCancel);
+ ui.el.addEventListener('hidden.bs.modal', onHidden);
+ ui.modal.show();
+ });
+ }
+
+ function queueConfirm(message, options) {
+ var run = function () {
+ return showConfirmDialog(message, options);
+ };
+ var pending = confirmQueue.then(run, run);
+ confirmQueue = pending.catch(function () { return false; });
+ return pending;
+ }
+
+ function installConfirmForForms() {
+ document.addEventListener('submit', function (event) {
+ var form = event.target;
+ if (!(form instanceof HTMLFormElement)) return;
+ if (!form.matches('form[data-confirm]')) return;
+
+ if (form.dataset.confirmBypass === '1') {
+ form.dataset.confirmBypass = '';
+ return;
+ }
+
+ event.preventDefault();
+ queueConfirm(form.getAttribute('data-confirm'), {
+ title: form.dataset.confirmTitle || 'Potwierdzenie',
+ confirmText: form.dataset.confirmOk || 'Potwierdz',
+ cancelText: form.dataset.confirmCancel || 'Anuluj',
+ confirmClass: form.dataset.confirmClass || 'btn-danger'
+ }).then(function (ok) {
+ if (!ok) return;
+ form.dataset.confirmBypass = '1';
+ form.submit();
+ });
+ }, true);
+ }
+
+ function initTestConnectionButtons() {
+ document.querySelectorAll('.btn-test-connection').forEach(function (btn) {
+ btn.addEventListener('click', function () {
+ var siteId = this.dataset.siteId;
+ var button = this;
+ var originalHtml = button.innerHTML;
+
+ button.innerHTML = '';
+ button.disabled = true;
+
+ fetch('/sites/' + siteId + '/test', { method: 'POST' })
+ .then(function (r) { return r.json(); })
+ .then(function (data) {
+ if (data.success) {
+ button.innerHTML = '';
+ button.classList.remove('btn-outline-success');
+ button.classList.add('btn-success');
+ showToast(data.message || 'Polaczenie poprawne.', 'success', { delay: 3500 });
+ } else {
+ button.innerHTML = '';
+ button.classList.remove('btn-outline-success');
+ button.classList.add('btn-danger');
+ showToast('Blad polaczenia: ' + (data.message || 'Nieznany blad'), 'danger');
+ }
+ })
+ .catch(function () {
+ button.innerHTML = '';
+ button.classList.add('btn-danger');
+ showToast('Blad sieci podczas testu polaczenia.', 'danger');
+ })
+ .finally(function () {
+ button.disabled = false;
+ setTimeout(function () {
+ button.innerHTML = originalHtml;
+ button.className = button.className.replace('btn-success', 'btn-outline-success').replace('btn-danger', 'btn-outline-success');
+ }, 3000);
+ });
+ });
+ });
+ }
+
+ function initTopicEditButtons() {
+ document.querySelectorAll('.btn-edit-topic').forEach(function (btn) {
+ btn.addEventListener('click', function () {
+ var id = this.dataset.id;
+ var form = document.getElementById('topicForm');
+ var title = document.getElementById('topicFormTitle');
+ var submit = document.getElementById('topicFormSubmit');
+
+ if (!form || !title || !submit) return;
+
+ form.action = '/topics/' + id + '/update';
+ title.textContent = 'Edytuj temat';
+ submit.textContent = 'Zapisz zmiany';
+
+ document.getElementById('topic_name').value = this.dataset.name;
+ document.getElementById('topic_description').value = this.dataset.description;
+ document.getElementById('topic_wp_category').value = this.dataset.wpCategory || '';
+ document.getElementById('topic_is_active').checked = this.dataset.active === '1';
+
+ var globalSelect = document.getElementById('topic_global_id');
+ if (globalSelect) {
+ globalSelect.value = this.dataset.globalTopic || '';
+ }
+ });
+ });
+ }
+
+ function highlightActiveSidebarLink() {
+ var currentPath = window.location.pathname;
+ document.querySelectorAll('.sidebar .nav-link').forEach(function (link) {
+ var href = link.getAttribute('href');
+ if (currentPath === href || (href !== '/' && currentPath.startsWith(href))) {
+ link.classList.add('active');
}
});
- });
+ }
- // Highlight active sidebar link
- var currentPath = window.location.pathname;
- document.querySelectorAll('.sidebar .nav-link').forEach(function (link) {
- var href = link.getAttribute('href');
- if (currentPath === href || (href !== '/' && currentPath.startsWith(href))) {
- link.classList.add('active');
- }
+ window.BackProUI = {
+ toast: showToast,
+ confirm: queueConfirm
+ };
+
+ window.backproNotify = function (message, type, options) {
+ showToast(message, type || 'info', options);
+ };
+
+ window.backproConfirm = function (message, options) {
+ return queueConfirm(message, options);
+ };
+
+ document.addEventListener('DOMContentLoaded', function () {
+ installConfirmForForms();
+ initTestConnectionButtons();
+ initTopicEditButtons();
+ highlightActiveSidebarLink();
});
-});
+})();
diff --git a/assets/wp-theme-backpro-news/archive.php b/assets/wp-theme-backpro-news/archive.php
new file mode 100644
index 0000000..36af037
--- /dev/null
+++ b/assets/wp-theme-backpro-news/archive.php
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/wp-theme-backpro-news/footer.php b/assets/wp-theme-backpro-news/footer.php
new file mode 100644
index 0000000..d2a417d
--- /dev/null
+++ b/assets/wp-theme-backpro-news/footer.php
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+