</div>
</section>
- <!-- Tabella -->
- <table id="dataTable" class="table table-bordered table-hover align-middle d-none">
- <thead class="table-light">
- <tr>
- <th data-type="string" data-sortable="true" data-sort="0">Alias <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="1">Target <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="2">Description<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="3">Options <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false" data-sort="4">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
+ <!-- Tabella responsive -->
+ <div id="tableWrapper" class="table-responsive mobile-scroll d-none">
+ <table id="dataTable" class="table table-bordered table-hover align-middle">
+ <thead class="table-light">
+ <tr>
+ <th data-type="string" data-sortable="true" data-sort="0">Alias <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="1">Target <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="2">Description<span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="3">Options <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="false" data-sort="4">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
<!-- Loader -->
<div id="loader" class="text-center my-3" style="display: none;">
body {
font-family: sans-serif;
- margin: 20px;
- padding-top: 60px; /* space for fixed topbar */
+ margin: 0;
background-color: var(--bg-light);
color: var(--text-dark);
}
width: 100%;
background: var(--bg-dark);
border-bottom: 3px solid var(--accent);
- position: fixed;
+ position: sticky;
top: 0;
- left: 0;
z-index: 1000;
}
display: flex;
justify-content: space-between;
align-items: center;
+ flex-wrap: wrap;
+ gap: 10px;
}
.topbar .navbar {
background-color: var(--bg-frame);
border-left: 4px solid var(--accent);
padding: 6px 14px;
- margin-bottom: 25px;
box-shadow: 0 3px 6px rgba(0,0,0,0.18);
+ margin: 20px 20px 25px 20px;
}
.page-frame h2 {
border: none;
padding: 6px 14px;
font-size: 0.95rem;
- line-height: 1;
+ line-height: 1.2;
vertical-align: middle;
--icon-color: currentColor;
transition: all 0.2s ease;
================================ */
.icon,
i.bi {
- color: var(--icon-color);
- display: inline-flex;
- align-items: center;
+ color: var(--icon-color, currentColor);
+ vertical-align: middle;
}
.icon-static {
/* ================================
Table
================================ */
-.table {
- background-color: #fff;
+.table-responsive {
+ position: relative;
+ margin: 20px;
+ width: calc(100% - 40px);
+ max-height: calc(100vh - 185px);
+ overflow-x: auto;
+ overflow-y: auto;
+ border-radius: 10px;
box-shadow: 0 3px 6px rgba(0,0,0,0.18);
+ background-color: #fff;
+ -webkit-overflow-scrolling: touch;
+ border: 1px solid var(--border-light);
+}
+
+.table {
+ width: 100%; /* desktop full width */
+ min-width: max-content; /* mobile -> scroll */
+ margin: 0;
+ table-layout: auto;
border-color: var(--border-light);
+ border-style: hidden;
}
.table th,
.table td {
vertical-align: middle;
border-color: var(--border-light);
+ white-space: nowrap; /* niente wrap */
}
.table thead th {
background-color: #eee;
+ background-clip: padding-box;
font-weight: 700;
cursor: default;
user-select: none;
- position: relative;
+ position: sticky;
+ top: 0;
+ z-index: 2;
}
.table thead th:hover::after {
Responsive
================================ */
@media (max-width: 640px) {
- body {
- padding-top: 48px; /* topbar più compatta su mobile */
+
+ .topbar-inner {
+ flex-wrap: nowrap;
+ }
+
+ .topbar .navbar {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .logo span {
+ font-size: 1.1rem;
+ white-space: nowrap;
+ }
+
+ .page-frame {
+ margin: 10px 10px 15px 10px;
+ }
+
+ .table-responsive {
+ margin: 10px;
+ width: calc(100% - 20px);
+ max-height: calc(100dvh - 11.5rem);
+ }
+
+ .table {
+ font-size: 0.85rem;
+ }
+
+ .table th,
+ .table td {
+ padding: 0.45rem;
+ }
+
+ .btn {
+ padding-left: 0.6rem;
+ padding-right: 0.6rem;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
}
/* Toolbar: su schermi molto stretti mostra solo le icone dei bottoni */
display: none;
}
- .btn .icon {
+ .btn .icon,
+ .btn .bi {
margin-right: 0;
}
}
</div>
</section>
- <!-- Tabella -->
- <table id="dataTable" class="table table-bordered table-hover align-middle d-none">
- <thead class="table-light">
- <tr>
- <th data-type="ipv4" data-sortable="true" data-sort="0">IP Address <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="mac" data-sortable="true" data-sort="1">MAC Address<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="2">Hostname <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="3">Description<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="4">State <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="5">Active <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false" data-sort="6">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
+ <!-- Tabella responsive -->
+ <div id="tableWrapper" class="table-responsive mobile-scroll d-none">
+ <table id="dataTable" class="table table-bordered table-hover align-middle">
+ <thead class="table-light">
+ <tr>
+ <th data-type="ipv4" data-sortable="true" data-sort="0">IP Address <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="mac" data-sortable="true" data-sort="1">MAC Address<span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="2">Hostname <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="3">Description<span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="4">State <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="5">Active <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="false" data-sort="6">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
<!-- Loader -->
<div id="loader" class="text-center my-3" style="display: none;">
</div>
</section>
- <!-- Tabella -->
- <table id="dataTable" class="table table-bordered table-hover align-middle d-none">
- <thead class="table-light">
- <tr>
- <th data-type="string" data-sortable="true" data-sort="0">Hostname <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="ipv4" data-sortable="true" data-sort="1">IP Address <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="mac" data-sortable="true" data-sort="2">MAC Address<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="3">Description<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="4">Options <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false" data-sort="5">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
+ <!-- Tabella responsive -->
+ <div id="tableWrapper" class="table-responsive mobile-scroll d-none">
+ <table id="dataTable" class="table table-bordered table-hover align-middle">
+ <thead class="table-light">
+ <tr>
+ <th data-type="string" data-sortable="true" data-sort="0">Hostname <span class="sort-arrow"></span></th>
+ <th data-type="ipv4" data-sortable="true" data-sort="1">IP Address <span class="sort-arrow"></span></th>
+ <th data-type="mac" data-sortable="true" data-sort="2">MAC Address <span class="sort-arrow"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="3">Description <span class="sort-arrow"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="4">Options <span class="sort-arrow"></span></th>
+ <th data-type="string" data-sortable="false" data-sort="5">Actions <span class="sort-arrow"></span></th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
<!-- Loader -->
<div id="loader" class="text-center my-3" style="display: none;">
// -----------------------------
async function fetchAliases () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// hide table during loading to avoid flickering and show loader
- dataTable.classList.add("d-none");
+ tableWrapper.classList.add("d-none");
try {
// Show loader
viewAliases = [];
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
}
}
// -----------------------------
function updateTable () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.appendChild(trEmpty);
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
return;
}
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
// apply current search filter
const searchInput = document.getElementById("searchInput");
// -----------------------------
async function fetchDevices () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// hide table during loading to avoid flickering and show loader
- dataTable.classList.add("d-none");
+ tableWrapper.classList.add("d-none");
try {
// Show loader
viewDevices = [];
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
}
}
// -----------------------------
function updateTable () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.appendChild(trEmpty);
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
return;
}
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
// apply current search filter
const searchInput = document.getElementById("searchInput");
// -----------------------------
async function fetchHosts () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// hide table during loading to avoid flickering and show loader
- dataTable.classList.add("d-none");
+ tableWrapper.classList.add("d-none");
try {
// Show loader
viewHosts = [];
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
}
}
// -----------------------------
function updateTable () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.appendChild(trEmpty);
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
return;
}
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
// apply current search filter
const searchInput = document.getElementById("searchInput");
// -----------------------------
async function fetchLeases () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// hide table during loading to avoid flickering and show loader
- dataTable.classList.add("d-none");
+ tableWrapper.classList.add("d-none");
try {
// Show loader
viewLeases = [];
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
}
}
// -----------------------------
function updateTable () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.appendChild(trEmpty);
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
return;
}
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
// apply current search filter
const searchInput = document.getElementById("searchInput");
// -----------------------------
async function fetchConfigs () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
// hide table during loading to avoid flickering and show loader
- dataTable.classList.add("d-none");
+ tableWrapper.classList.add("d-none");
try {
// Show loader
viewConfigs = [];
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
}
}
// -----------------------------
function updateTable () {
const loader = document.getElementById("loader");
- const dataTable = document.getElementById("dataTable");
+ const tableWrapper = document.getElementById("tableWrapper");
const searchInput = document.getElementById("searchInput");
const term = searchInput?.value?.trim().toLowerCase();
const hasSearch = !!term;
tbody.appendChild(trEmpty);
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
return;
}
// hide loader and show table
loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ tableWrapper.classList.remove("d-none");
}
// -----------------------------
</div>
</section>
- <!-- Tabella -->
- <table id="dataTable" class="table table-bordered table-hover align-middle d-none">
- <thead class="table-light">
- <tr>
- <th data-type="ipv4" data-sortable="true" data-sort="0">IP Address<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="mac" data-sortable="true" data-sort="1">MAC <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="2">Hostname <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="3">Start <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="4">End <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="true" data-sort="5">State <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false" data-sort="6">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
+ <!-- Tabella responsive -->
+ <div id="tableWrapper" class="table-responsive mobile-scroll d-none">
+ <table id="dataTable" class="table table-bordered table-hover align-middle">
+ <thead class="table-light">
+ <tr>
+ <th data-type="ipv4" data-sortable="true" data-sort="0">IP Address<span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="mac" data-sortable="true" data-sort="1">MAC <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="2">Hostname <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="3">Start <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="4">End <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="true" data-sort="5">State <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="false" data-sort="6">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
<!-- Loader -->
<div id="loader" class="text-center my-3" style="display: none;">
</div>
</section>
- <!-- Tabella -->
- <table id="dataTable" class="table table-bordered table-hover align-middle d-none">
- <thead class="table-light">
- <tr>
- <th data-type="string" data-sortable="false">Parameter <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false">Value <span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false">Description<span class="sort-arrow" aria-hidden="true"></span></th>
- <th data-type="string" data-sortable="false">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
+ <!-- Tabella responsive -->
+ <div id="tableWrapper" class="table-responsive mobile-scroll d-none">
+ <table id="dataTable" class="table table-bordered table-hover align-middle">
+ <thead class="table-light">
+ <tr>
+ <th data-type="string" data-sortable="false">Parameter <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="false">Value <span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="false">Description<span class="sort-arrow" aria-hidden="true"></span></th>
+ <th data-type="string" data-sortable="false">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
<!-- Loader -->
<div id="loader" class="text-center my-3" style="display: none;">