This commit is contained in:
andre committed 2026-06-12 21:20:23 +01:00
1 parent e68d357177
commit 3e3382df57
65 files changed
+1836 -42

No files matched your search

+48
View File
@@ -3,7 +3,55 @@
?>
</div><!-- /.p-3 / .p-md-4 -->
</main>
<?= script_tag('assets/vendor/jquery/jquery-3.7.1.min.js') ?>
<?= script_tag('assets/vendor/bootstrap5/js/bootstrap.bundle.min.js') ?>
<?= script_tag('assets/vendor/summernote/summernote-bs5.min.js') ?>
<?= script_tag('assets/vendor/summernote/lang/summernote-pt-PT.min.js') ?>
<script>
// Attach Summernote to any <textarea class="js-wysiwyg">. The editor keeps the
// underlying textarea in sync, so normal form POSTs submit the generated HTML.
// Inline image upload is intentionally omitted (base64 would bloat the row) —
// modules that need images use their own file-upload fields.
document.addEventListener('DOMContentLoaded', function () {
if (!window.jQuery || !jQuery.fn || !jQuery.fn.summernote) return;
jQuery('textarea.js-wysiwyg').each(function () {
var $ta = jQuery(this);
$ta.summernote({
lang: 'pt-PT',
height: parseInt($ta.data('wysiwyg-height'), 10) || 240,
disableDragAndDrop: true,
toolbar: [
['style', ['style']],
['font', ['bold', 'italic', 'underline', 'clear']],
['para', ['ul', 'ol', 'paragraph']],
['insert', ['link']],
['view', ['codeview', 'fullscreen']]
],
styleTags: ['p', 'h2', 'h3', 'h4', 'blockquote'],
popover: { image: [], air: [] }
});
});
});
// Mobile off-canvas sidebar: hamburger toggles .sidebar.open + the backdrop;
// tapping the backdrop, a nav link, Escape, or resizing to desktop closes it.
(function () {
var sb = document.getElementById('sidebar');
var tg = document.getElementById('menuToggle');
var bd = document.getElementById('sidebarBackdrop');
if (!sb || !tg) return;
var mq = window.matchMedia('(max-width: 991.98px)');
function open() { sb.classList.add('open'); if (bd) bd.classList.add('show'); document.body.style.overflow = 'hidden'; tg.setAttribute('aria-expanded', 'true'); }
function close() { sb.classList.remove('open'); if (bd) bd.classList.remove('show'); document.body.style.overflow = ''; tg.setAttribute('aria-expanded', 'false'); }
tg.addEventListener('click', function () { sb.classList.contains('open') ? close() : open(); });
if (bd) bd.addEventListener('click', close);
sb.querySelectorAll('.nav-link').forEach(function (a) {
a.addEventListener('click', function () { if (mq.matches) close(); });
});
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
window.addEventListener('resize', function () { if (!mq.matches) close(); });
})();
</script>
<style>
/* Console footer — subtle brand bar */
main:after {
+46 -4
View File
@@ -13,6 +13,7 @@ $app_name = defined('APP_NAME') ? APP_NAME : 'FitMe 3070';
<title><?= htmlspecialchars($page_title) ?> — <?= htmlspecialchars($app_name) ?></title>
<link href="<?= base_url('assets/vendor/bootstrap5/css/bootstrap.min.css') ?>" rel="stylesheet">
<link href="<?= base_url('assets/vendor/bootstrap-icons/bootstrap-icons.css') ?>" rel="stylesheet">
<link href="<?= base_url('assets/vendor/summernote/summernote-bs5.min.css') ?>" rel="stylesheet">
<style>
:root {
--bo-accent: #C2D500;
@@ -39,7 +40,7 @@ $app_name = defined('APP_NAME') ? APP_NAME : 'FitMe 3070';
.topbar { position: fixed; top: 0; left: 240px; right: 0; z-index: 99; height: 56px;
background: #fff; border-bottom: 1px solid #e2e6ec; padding: 0 1.5rem;
display: flex; align-items: center; justify-content: space-between; }
.topbar .user-dropdown { display: flex; align-items: center; gap: .5rem; }
.topbar .user-dropdown { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.badge-role-sysadmin { background: var(--bo-accent); color: var(--bo-dark); }
.badge-role-admin { background: var(--bo-accent); color: var(--bo-dark); opacity: .85; }
.badge-role-staff { background: #6f42c1; }
@@ -50,10 +51,44 @@ $app_name = defined('APP_NAME') ? APP_NAME : 'FitMe 3070';
.btn-primary:hover { background: #a8ba00; border-color: #a8ba00; color: var(--bo-dark); }
.card { border: none; box-shadow: 0 1px 3px rgba(0,0,0,.04); }
a { color: #0a0a0a; }
/* Summernote (WYSIWYG) — align with the backoffice look */
.note-editor.note-frame { border-color: #ced4da; border-radius: .375rem; }
.note-editor .note-editing-area .note-editable { font-size: .95rem; }
.note-editor.note-frame.note-focused { border-color: var(--bo-accent); box-shadow: 0 0 0 .2rem rgba(var(--bo-accent-rgb), .25); }
.note-toolbar { background: #f8f9fa; }
.note-btn.btn-primary { background: var(--bo-accent); border-color: var(--bo-accent); color: var(--bo-dark); }
/* ── Mobile: off-canvas sidebar + hamburger ──────────────────────────── */
.sidebar { transition: transform .25s ease; }
.menu-toggle { display: none; width: 40px; height: 40px; padding: 0; border: 1px solid #e2e6ec;
background: #fff; color: var(--bo-dark); border-radius: 8px; font-size: 1.35rem;
line-height: 1; align-items: center; justify-content: center; }
.sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 1090; background: rgba(0,0,0,.45); }
.sidebar-backdrop.show { display: block; }
@media (max-width: 991.98px) {
.sidebar { transform: translateX(-100%); width: 264px; z-index: 1100;
box-shadow: 2px 0 18px rgba(0,0,0,.3); }
.sidebar .sidebar-brand { width: 264px; z-index: 1101; }
.sidebar.open { transform: translateX(0); }
main { margin-left: 0; }
.topbar { left: 0; padding: 0 .75rem; }
.menu-toggle { display: inline-flex; }
/* Wide tables scroll inside their card instead of overflowing the page */
main .card > .card-body { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
@media (max-width: 575.98px) {
.topbar .user-dropdown .badge,
.topbar .user-dropdown .u-name { display: none; }
/* Page-header rows (title + action buttons) stack instead of overflowing */
main .d-flex.justify-content-between.align-items-center { flex-wrap: wrap; gap: .5rem; }
/* 16px inputs stop iOS from auto-zooming on focus */
.form-control, .form-select { font-size: 16px; }
/* Comfortable content gutters on phones */
.p-3 { padding: .85rem !important; }
}
</style>
</head>
<body>
<nav class="sidebar">
<nav class="sidebar" id="sidebar">
<div class="sidebar-brand"><i class="bi bi-lightning-charge-fill me-2"></i><?= htmlspecialchars($app_name) ?></div>
<div class="sidebar-section">Principal</div>
<ul class="nav flex-column">
@@ -83,6 +118,10 @@ $app_name = defined('APP_NAME') ? APP_NAME : 'FitMe 3070';
<a class="nav-link<?= (strpos($_SERVER['SCRIPT_NAME'] ?? '', '/views/admin/galerias/') !== false) ? ' active' : '' ?>"
href="<?= base_url('views/admin/galerias/index.php') ?>"><i class="bi bi-images"></i>Galerias</a>
</li>
<li class="nav-item">
<a class="nav-link<?= (strpos($_SERVER['SCRIPT_NAME'] ?? '', '/views/admin/events/') !== false) ? ' active' : '' ?>"
href="<?= base_url('views/admin/events/index.php') ?>"><i class="bi bi-megaphone-fill"></i>Eventos</a>
</li>
<li class="nav-item">
<a class="nav-link<?= (strpos($_SERVER['SCRIPT_NAME'] ?? '', '/views/admin/work_hours/') !== false) ? ' active' : '' ?>"
href="<?= base_url('views/admin/work_hours/index.php') ?>"><i class="bi bi-clock-fill"></i>Horário de Funcionamento</a>
@@ -122,15 +161,18 @@ $app_name = defined('APP_NAME') ? APP_NAME : 'FitMe 3070';
</ul>
<?php endif; ?>
</nav>
<div class="sidebar-backdrop" id="sidebarBackdrop" aria-hidden="true"></div>
<main>
<div class="topbar">
<div></div>
<button type="button" class="menu-toggle" id="menuToggle" aria-label="Abrir menu" aria-controls="sidebar">
<i class="bi bi-list"></i>
</button>
<div class="user-dropdown">
<span class="badge rounded-pill badge-role-<?= htmlspecialchars($user['role']) ?>">
<?= htmlspecialchars(role_label($user['role'])) ?>
</span>
<span><?= htmlspecialchars($user['name']) ?></span>
<span class="u-name"><?= htmlspecialchars($user['name']) ?></span>
<a href="<?= base_url('views/user/profile.php') ?>" class="btn btn-sm btn-outline-secondary"><i class="bi bi-person"></i></a>
<a href="<?= base_url('views/auth/logout.php') ?>" class="btn btn-sm btn-outline-danger"><i class="bi bi-box-arrow-right"></i></a>
</div>