161 lines
8.3 KiB
PHP
161 lines
8.3 KiB
PHP
|
|
</main>
|
|
</div>
|
|
<script>
|
|
// ── Dark Mode Toggle ──────────────────────────────────────────────────
|
|
const themeBtn = document.getElementById('theme-toggle');
|
|
const iconLight = document.getElementById('theme-icon-light');
|
|
const iconDark = document.getElementById('theme-icon-dark');
|
|
|
|
function updateThemeIcon() {
|
|
if(document.body.classList.contains('dark-mode')) {
|
|
iconLight.style.display = 'block';
|
|
iconDark.style.display = 'none';
|
|
} else {
|
|
iconLight.style.display = 'none';
|
|
iconDark.style.display = 'block';
|
|
}
|
|
}
|
|
if(themeBtn) {
|
|
updateThemeIcon();
|
|
themeBtn.addEventListener('click', () => {
|
|
document.body.classList.toggle('dark-mode');
|
|
const isDark = document.body.classList.contains('dark-mode');
|
|
localStorage.setItem('theme', isDark ? 'dark' : 'light');
|
|
updateThemeIcon();
|
|
});
|
|
}
|
|
|
|
// ── Toast ─────────────────────────────────────────────────────────────
|
|
function showToast(msg) {
|
|
const t = document.getElementById('toast');
|
|
t.textContent = msg;
|
|
t.classList.add('show');
|
|
setTimeout(() => t.classList.remove('show'), 3000);
|
|
}
|
|
|
|
// ── Custom Alert / Confirm ─────────────────────────────────────────────
|
|
function appAlert(msg) {
|
|
return new Promise(resolve => {
|
|
let modal = document.getElementById('app-alert-modal');
|
|
if(!modal) {
|
|
modal = document.createElement('div');
|
|
modal.id = 'app-alert-modal';
|
|
modal.className = 'modal-overlay';
|
|
modal.style.zIndex = '10005';
|
|
modal.innerHTML = `
|
|
<div class="modal-content" style="max-width:320px; text-align:center;">
|
|
<h3 style="margin-bottom:1rem; font-size:1.1rem;">Notice</h3>
|
|
<p style="margin-bottom:1.5rem; font-size:0.9rem; color:var(--text);" id="app-alert-msg"></p>
|
|
<button class="btn" style="width:100%;" id="app-alert-ok">OK</button>
|
|
</div>`;
|
|
document.body.appendChild(modal);
|
|
}
|
|
document.getElementById('app-alert-msg').textContent = msg;
|
|
modal.classList.add('active');
|
|
document.getElementById('app-alert-ok').onclick = () => { modal.classList.remove('active'); resolve(true); };
|
|
});
|
|
}
|
|
window.alert = function(msg) { appAlert(msg); };
|
|
|
|
function appConfirm(msg) {
|
|
return new Promise(resolve => {
|
|
let modal = document.getElementById('app-confirm-modal');
|
|
if(!modal) {
|
|
modal = document.createElement('div');
|
|
modal.id = 'app-confirm-modal';
|
|
modal.className = 'modal-overlay';
|
|
modal.style.zIndex = '10005';
|
|
modal.innerHTML = `
|
|
<div class="modal-content" style="max-width:350px;">
|
|
<h3 style="margin-bottom:0.75rem; font-size:1.1rem; text-align:center;">Confirmation</h3>
|
|
<p style="margin-bottom:1.5rem; font-size:0.95rem; color:var(--text); text-align:center; line-height:1.4;" id="app-confirm-msg"></p>
|
|
<div style="display:flex; gap:0.5rem;">
|
|
<button class="btn btn-secondary" style="flex:1;" id="app-confirm-no">Cancel</button>
|
|
<button class="btn btn-danger" style="flex:1;" id="app-confirm-yes">Confirm</button>
|
|
</div>
|
|
</div>`;
|
|
document.body.appendChild(modal);
|
|
}
|
|
document.getElementById('app-confirm-msg').textContent = msg;
|
|
modal.classList.add('active');
|
|
document.getElementById('app-confirm-no').onclick = () => { modal.classList.remove('active'); resolve(false); };
|
|
document.getElementById('app-confirm-yes').onclick = () => { modal.classList.remove('active'); resolve(true); };
|
|
});
|
|
}
|
|
|
|
function appConfirmUrl(event, url, msg) {
|
|
event.preventDefault();
|
|
appConfirm(msg).then(yes => { if(yes) window.location.href = url; });
|
|
}
|
|
|
|
// ── Sidebar Collapse ──────────────────────────────────────────────────
|
|
function toggleSidebar() {
|
|
const collapsed = document.body.classList.toggle('sidebar-collapsed');
|
|
localStorage.setItem('sidebar_collapsed', collapsed ? '1' : '0');
|
|
updateSidebarIcon();
|
|
}
|
|
function updateSidebarIcon() {
|
|
const icon = document.getElementById('sidebar-toggle-icon');
|
|
if(!icon) return;
|
|
if(document.body.classList.contains('sidebar-collapsed')) {
|
|
icon.className = 'fa fa-chevron-right';
|
|
} else {
|
|
icon.className = 'fa fa-chevron-left';
|
|
}
|
|
}
|
|
updateSidebarIcon();
|
|
|
|
// ── User Dropdown ─────────────────────────────────────────────────────
|
|
function toggleUserDropdown() {
|
|
const menu = document.getElementById('user-dropdown-menu');
|
|
menu.classList.toggle('open');
|
|
}
|
|
function closeUserDropdown() {
|
|
const menu = document.getElementById('user-dropdown-menu');
|
|
if(menu) menu.classList.remove('open');
|
|
}
|
|
document.addEventListener('click', (e) => {
|
|
const wrap = document.getElementById('user-dropdown-wrap');
|
|
if (wrap && !wrap.contains(e.target)) closeUserDropdown();
|
|
});
|
|
|
|
// ── Notifications ─────────────────────────────────────────────────────
|
|
function openNotifications() {
|
|
closeUserDropdown();
|
|
document.getElementById('notifications-modal').classList.add('active');
|
|
}
|
|
|
|
// ── Close modals on overlay click ─────────────────────────────────────
|
|
document.querySelectorAll('.modal-overlay').forEach(mo => {
|
|
mo.addEventListener('click', (e) => {
|
|
if (e.target === mo) mo.classList.remove('active');
|
|
});
|
|
});
|
|
|
|
// ── Auto open change-pw modal if error ────────────────────────────────
|
|
<?php
|
|
$pw_msg_bottom = $_SESSION['pw_change_msg_bottom'] ?? null;
|
|
if($pw_msg_bottom):
|
|
?>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
document.getElementById('change-pw-modal').classList.add('active');
|
|
});
|
|
<?php endif; ?>
|
|
|
|
// ── Tagify globally ───────────────────────────────────────────────────
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if(typeof Tagify !== 'undefined' && window.APP_GLOBAL_TAGS) {
|
|
document.querySelectorAll('.tagify-input').forEach(el => {
|
|
new Tagify(el, {
|
|
whitelist: window.APP_GLOBAL_TAGS,
|
|
dropdown: { maxItems: 20, classname: "tags-look", enabled: 0, closeOnSelect: false },
|
|
originalInputValueFormat: valuesArr => valuesArr.map(item => item.value).join(',')
|
|
});
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|