Dodaj stylizowane modale i link Audyt SEO w menu admina
- Zamieniono natywne confirm/alert na ładne modale CSS - Dodano link "Audyt SEO" w menu administracyjnym - Modal z animacją slide-in, ikony ostrzeżenia/info - Obsługa zamykania przez backdrop Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
892cfcc39a
commit
90ca2bc618
@ -347,6 +347,95 @@
|
|||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Modal styles */
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background: var(--surface);
|
||||||
|
padding: var(--spacing-xl);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
max-width: 480px;
|
||||||
|
width: 90%;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
animation: modalSlideIn 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes modalSlideIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-md);
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-icon.warning {
|
||||||
|
background: #fef3c7;
|
||||||
|
color: #d97706;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-icon.success {
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-icon.info {
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: var(--font-size-xl);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: var(--spacing-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -570,11 +659,92 @@
|
|||||||
<p>Nie znaleziono firm z danymi SEO.</p>
|
<p>Nie znaleziono firm z danymi SEO.</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Confirmation Modal -->
|
||||||
|
<div class="modal" id="confirmModal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="modal-icon warning">
|
||||||
|
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="modal-title" id="modalTitle">Potwierdz operacje</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="modalBody">
|
||||||
|
Czy na pewno chcesz wykonac te operacje?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-outline" onclick="closeModal()">Anuluj</button>
|
||||||
|
<button class="btn btn-primary" onclick="confirmModalAction()">Potwierdz</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Modal -->
|
||||||
|
<div class="modal" id="infoModal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="modal-icon info">
|
||||||
|
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="modal-title" id="infoModalTitle">Informacja</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="infoModalBody">
|
||||||
|
Tresc informacji.
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-primary" onclick="closeInfoModal()">OK</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
const csrfToken = '{{ csrf_token() }}';
|
const csrfToken = '{{ csrf_token() }}';
|
||||||
|
|
||||||
|
// Modal functions
|
||||||
|
let pendingModalAction = null;
|
||||||
|
|
||||||
|
function showModal(title, body, onConfirm) {
|
||||||
|
document.getElementById('modalTitle').textContent = title;
|
||||||
|
document.getElementById('modalBody').textContent = body;
|
||||||
|
pendingModalAction = onConfirm;
|
||||||
|
document.getElementById('confirmModal').classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
document.getElementById('confirmModal').classList.remove('active');
|
||||||
|
pendingModalAction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmModalAction() {
|
||||||
|
if (pendingModalAction) {
|
||||||
|
pendingModalAction();
|
||||||
|
}
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showInfoModal(title, body) {
|
||||||
|
document.getElementById('infoModalTitle').textContent = title;
|
||||||
|
document.getElementById('infoModalBody').textContent = body;
|
||||||
|
document.getElementById('infoModal').classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeInfoModal() {
|
||||||
|
document.getElementById('infoModal').classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close modal on backdrop click
|
||||||
|
document.getElementById('confirmModal')?.addEventListener('click', (e) => {
|
||||||
|
if (e.target.id === 'confirmModal') closeModal();
|
||||||
|
});
|
||||||
|
document.getElementById('infoModal')?.addEventListener('click', (e) => {
|
||||||
|
if (e.target.id === 'infoModal') closeInfoModal();
|
||||||
|
});
|
||||||
|
|
||||||
// Sorting state
|
// Sorting state
|
||||||
let currentSort = { column: 'overall', direction: 'desc' };
|
let currentSort = { column: 'overall', direction: 'desc' };
|
||||||
|
|
||||||
@ -676,47 +846,53 @@ function resetFilters() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Audit functions
|
// Audit functions
|
||||||
async function runSingleAudit(slug) {
|
function runSingleAudit(slug) {
|
||||||
if (!confirm('Czy na pewno chcesz uruchomic audyt SEO dla tej firmy? Moze to potrwac kilka minut.')) {
|
showModal(
|
||||||
return;
|
'Uruchom audyt SEO',
|
||||||
}
|
'Czy na pewno chcesz uruchomić audyt SEO dla tej firmy? Analiza może potrwać kilka minut.',
|
||||||
|
async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/seo/audit', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ slug: slug })
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
const data = await response.json();
|
||||||
const response = await fetch('/api/seo/audit', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': csrfToken
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ slug: slug })
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
if (response.ok && data.success) {
|
||||||
|
showInfoModal('Audyt zakończony', 'Audyt SEO zakończony pomyślnie! Strona zostanie odświeżona.');
|
||||||
if (response.ok && data.success) {
|
setTimeout(() => location.reload(), 1500);
|
||||||
alert('Audyt SEO zakonczony pomyslnie! Odswiezam strone...');
|
} else {
|
||||||
location.reload();
|
showInfoModal('Błąd', 'Wystąpił błąd: ' + (data.error || 'Nieznany błąd'));
|
||||||
} else {
|
}
|
||||||
alert('Blad: ' + (data.error || 'Nieznany blad'));
|
} catch (error) {
|
||||||
|
showInfoModal('Błąd połączenia', 'Nie udało się połączyć z serwerem: ' + error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
);
|
||||||
alert('Blad polaczenia: ' + error.message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runBatchAudit() {
|
function runBatchAudit() {
|
||||||
if (!confirm('Czy na pewno chcesz uruchomic audyt SEO dla wszystkich firm? To moze potrwac dluzszy czas.')) {
|
showModal(
|
||||||
return;
|
'Uruchom audyt wsadowy',
|
||||||
}
|
'Czy na pewno chcesz uruchomić audyt SEO dla wszystkich firm? To może potrwać dłuższy czas.',
|
||||||
|
() => {
|
||||||
|
const btn = document.getElementById('batchAuditBtn');
|
||||||
|
const originalText = btn.innerHTML;
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerHTML = '<span>Audyt w toku...</span>';
|
||||||
|
|
||||||
const btn = document.getElementById('batchAuditBtn');
|
showInfoModal('Audyt uruchomiony', 'Audyt wsadowy został uruchomiony w tle. Może to potrwać kilkadziesiąt minut. Sprawdź wyniki później.');
|
||||||
const originalText = btn.innerHTML;
|
|
||||||
btn.disabled = true;
|
|
||||||
btn.innerHTML = '<span>Audyt w toku...</span>';
|
|
||||||
|
|
||||||
alert('Audyt wsadowy zostanie uruchomiony w tle. Moze to potrwac kilkadziesiat minut. Sprawdz wyniki pozniej.');
|
setTimeout(() => {
|
||||||
|
btn.disabled = false;
|
||||||
btn.disabled = false;
|
btn.innerHTML = originalText;
|
||||||
btn.innerHTML = originalText;
|
}, 2000);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -858,6 +858,7 @@
|
|||||||
<a href="{{ url_for('admin_fees') }}" class="user-menu-item">Składki członkowskie</a>
|
<a href="{{ url_for('admin_fees') }}" class="user-menu-item">Składki członkowskie</a>
|
||||||
<a href="{{ url_for('admin_calendar') }}" class="user-menu-item">Kalendarz</a>
|
<a href="{{ url_for('admin_calendar') }}" class="user-menu-item">Kalendarz</a>
|
||||||
<a href="{{ url_for('admin_social_media') }}" class="user-menu-item">Social Media</a>
|
<a href="{{ url_for('admin_social_media') }}" class="user-menu-item">Social Media</a>
|
||||||
|
<a href="{{ url_for('admin_seo') }}" class="user-menu-item">Audyt SEO</a>
|
||||||
<a href="{{ url_for('chat_analytics') }}" class="user-menu-item">Analityka Chatu</a>
|
<a href="{{ url_for('chat_analytics') }}" class="user-menu-item">Analityka Chatu</a>
|
||||||
<a href="{{ url_for('debug_panel') }}" class="user-menu-item">Debug Panel</a>
|
<a href="{{ url_for('debug_panel') }}" class="user-menu-item">Debug Panel</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user