Fix mobile layout issues

This commit is contained in:
2025-06-21 06:44:35 +02:00
parent 4a5874d4f8
commit 5985a726e3
15 changed files with 229 additions and 45 deletions

View File

@ -16,7 +16,7 @@
<!-- Sidebar --> <!-- Sidebar -->
<aside class="hidden md:flex md:w-64 flex-col h-full min-h-screen bg-white border-r border-gray-300 dark:bg-gray-800 dark:border-gray-700" id="sidebar" aria-label="sidebar"> <aside class="hidden lg:flex lg:w-64 flex-col h-full min-h-screen bg-white border-r border-gray-300 dark:bg-gray-800 dark:border-gray-700" id="sidebar" aria-label="sidebar">
{% include "base/partials/sidebar.html.j2" %} {% include "base/partials/sidebar.html.j2" %}
</aside> </aside>
<!-- Main Panel --> <!-- Main Panel -->

View File

@ -2,25 +2,58 @@
{% block page_content %} {% block page_content %}
<!-- Master-Detail Split View --> <!-- Master-Detail Split View -->
<div class="flex h-[calc(100vh-3.5rem)] overflow-hidden"> <div class="flex h-[calc(100vh-5.5rem)] lg:h-[calc(100vh-3.5rem)] overflow-hidden">
<!-- Master Pane --> <!-- Master Pane -->
<aside id="master-pane" <aside id="master-pane"
class="md:w-80 w-full shrink-0 border-r overflow-y-auto bg-white md:block border-gray-200 p-4 dark:bg-gray-800 dark:border-gray-700"> class="lg:w-80 w-full shrink-0 border-r overflow-y-auto bg-white lg:block border-gray-200 p-4 dark:bg-gray-800 dark:border-gray-700 {% if mobile_show_details|default(false) -%} hidden{% endif -%}">
{% block master %} {% block master %}
<p class="p-4 text-gray-500">Master view (e.g. list/tree)</p> <p class="p-4 text-gray-500">Master view (e.g. list/tree)</p>
{% endblock %} {% endblock %}
</aside> </aside>
<!-- Detail Pane --> <!-- Detail Pane -->
<section id="detail-pane"
class="flex-1 flex overflow-y-auto bg-white p-4 hidden md:block dark:bg-gray-800"> <section id="detail-pane"
{% block detail %} class="flex-1 flex overflow-y-auto bg-white p-4 {%- if not mobile_show_details|default(false) -%} hidden{%- endif -%} lg:block dark:bg-gray-800">
<p class="p-4 text-gray-500 dark:text-gray-200">Select an item to view details</p>
{% block detail %}
<p class="p-4 text-gray-500 dark:text-gray-200">Select an item to view details</p>
{% endblock %}
<div class="lg:hidden h-16 block">
&nbsp;
</div>
</section>
{% block master_detail_nav %}
{# mobile navigation for master-detail views #}
<div class="lg:hidden fixed bottom-0 left-0 z-10 w-full h-16 bg-white border-t border-gray-200 dark:bg-gray-700 dark:border-gray-600">
<section id="bottom-toolbar"
class="flex-1 flex grid grid-cols-2 blace-content-between">
<div class="flex w-full justify-start">
<sl-tooltip content="Back to list">
<sl-icon-button name="caret-left" label="back" id="showMasterBtn" style="font-size: 2.5rem;"></sl-icon-button>
</sl-tooltip>
</div>
<div class="flex w-full justify-end">
<sl-tooltip content="Show Details">
<sl-icon-button name="caret-right" label="back" id="showDetailsBtn" style="font-size: 2.5rem;"></sl-icon-button>
</sl-tooltip>
</div>
</section>
</div>
{% endblock %} {% endblock %}
</section>
</div>
</div> </div>
<script>
{% include '/base/partials/master-detail-nav.js' %}
</script>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,51 @@
function toggleDetails() {
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
masterPane.classList.toggle("hidden");
detailPane.classList.toggle("hidden");
}
function showDetails() {
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
masterPane.classList.add("hidden");
detailPane.classList.remove("hidden");
}
function showMaster() {
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
masterPane.classList.remove("hidden");
detailPane.classList.add("hidden");
}
function addBtnEvent() {
const showDetailsBtn = document.getElementById("showDetailsBtn");
const showMasterBtn = document.getElementById("showMasterBtn");
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
if (!showDetailsBtn) {
console.log("Can't find the button!");
return;
}
showMasterBtn.addEventListener("click", () => {
showMaster();
});
showDetailsBtn.addEventListener("click", () => {
showDetails();
});
}
document.addEventListener("DOMContentLoaded", () => {
addBtnEvent();
});
document.addEventListener("htmx:afterSettle", () => {
addBtnEvent();
});

View File

@ -8,7 +8,7 @@
id="sidebar-toggle" id="sidebar-toggle"
aria-expanded="true" aria-expanded="true"
aria-controls="mobile-sidebar" aria-controls="mobile-sidebar"
class="md:hidden text-gray-600 hover:text-gray-900 focus:outline-none" class="lg:hidden text-gray-600 hover:text-gray-900 focus:outline-none"
aria-label="Toggle sidebar" aria-label="Toggle sidebar"
> >
<sl-icon name="list" class="text-xl"></sl-icon> <sl-icon name="list" class="text-xl"></sl-icon>

View File

@ -5,6 +5,7 @@
<div id="client-tree"> <div id="client-tree">
{% include '/clients/partials/tree.html.j2' %} {% include '/clients/partials/tree.html.j2' %}
</div> </div>
{% include '/clients/partials/drawer_create.html.j2' %}
{% endblock %} {% endblock %}
@ -13,9 +14,9 @@
<div id="clientdetails" class="w-full"> <div id="clientdetails" class="w-full">
{% include '/clients/partials/client_details.html.j2' %} {% include '/clients/partials/client_details.html.j2' %}
</div> </div>
<!-- after clientdetails -->
{% endblock %} {% endblock %}
{% include '/clients/partials/drawer_create.html.j2' %}
{% block local_scripts %} {% block local_scripts %}
<script> <script>
{% include '/clients/partials/tree_event.js' %} {% include '/clients/partials/tree_event.js' %}

View File

@ -1,6 +1,9 @@
<!-- menu --> <!-- menu -->
<div class="flowbite-init-target"> <div class="flowbite-init-target">
<!-- start of client details inner -->
<div class="flex justify-end px-4"> <div class="flex justify-end px-4">
<button id="client-menu-button" data-dropdown-toggle="client-edit-menu" class="inline-block text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-4 focus:outline-none focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-1.5" type="button"> <button id="client-menu-button" data-dropdown-toggle="client-edit-menu" class="inline-block text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-4 focus:outline-none focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-1.5" type="button">
<span class="sr-only">Open dropdown</span> <span class="sr-only">Open dropdown</span>
@ -38,6 +41,8 @@
</ul> </ul>
</div> </div>
</div> </div>
<sl-tab-group > <sl-tab-group >
<sl-tab slot="nav" panel="client_data">Client Data</sl-tab> <sl-tab slot="nav" panel="client_data">Client Data</sl-tab>
<sl-tab slot="nav" panel="events">Events</sl-tab> <sl-tab slot="nav" panel="events">Events</sl-tab>
@ -84,12 +89,14 @@
</div> </div>
</div> </div>
</sl-tab-panel> </sl-tab-panel>
<sl-tab-panel name="events"> <sl-tab-panel name="events">
<div id="client-audit-events"> <div id="client-audit-events">
{% include '/clients/partials/client_events.html.j2' %} {% include '/clients/partials/client_events.html.j2' %}
</div> </div>
</sl-tab-panel> </sl-tab-panel>
</sl-tab-group> </sl-tab-group>
</div>
{% include '/clients/partials/drawer_edit.html.j2' %} </div>
<!-- end of client details -->
{% include '/clients/partials/drawer_edit.html.j2' %}

View File

@ -91,6 +91,7 @@
<div <div
class="sticky bottom-0 right-0 items-center w-full p-4 bg-white border-t border-gray-200 sm:flex sm:justify-between dark:bg-gray-800 dark:border-gray-700" class="sticky bottom-0 right-0 items-center w-full p-4 bg-white border-t border-gray-200 sm:flex sm:justify-between dark:bg-gray-800 dark:border-gray-700"
> >
<div class="flex items-center mb-4 sm:mb-0"> <div class="flex items-center mb-4 sm:mb-0">
<span class="text-sm font-normal text-gray-500 dark:text-gray-400" <span class="text-sm font-normal text-gray-500 dark:text-gray-400"
@ -100,11 +101,10 @@
{% else %} {% else %}
<span class="font-semibold text-gray-900 dark:text-white">{{events_paging.first }}-{{ events_paging.last}}</span> of <span class="font-semibold text-gray-900 dark:text-white">{{events_paging.first }}-{{ events_paging.last}}</span> of
{% endif %} {% endif %}
<span class="font-semibold text-gray-900 dark:text-white" <span class="font-semibold text-gray-900 dark:text-white">{{ events_paging.total }}</span>
>{{ events_paging.total }}</span </span>
></span
>
</div> </div>
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-3">
<div class="flex space-x-1"> <div class="flex space-x-1">
@ -139,19 +139,20 @@
</button> </button>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<button
{% if events_paging.page < events_paging.total_pages %} {% if events_paging.page < events_paging.total_pages %}
<button
class="px-3 py-1 min-w-9 min-h-9 text-sm font-normal text-white bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 transition duration-200 ease" class="px-3 py-1 min-w-9 min-h-9 text-sm font-normal text-white bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 transition duration-200 ease"
hx-get="/clients/client/{{ client.id }}/events/{{ events_paging.page + 1 }}"
hx-get="/clients/client/{{ client.id }}/events/{{ events_paging.page + 1 }}" hx-target="#client-audit-events">
hx-target="#client-audit-events" Next
</button>
{% else %} {% else %}
class="px-3 py-1 min-w-9 min-h-9 text-sm font-normal text-gray-900 bg-white border border-gray-300 rounded hover:bg-gray-100 focus:ring-4 focus:ring-primary-300 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 transition duration-200 ease" <button
disabled="" class="px-3 py-1 min-w-9 min-h-9 text-sm font-normal text-gray-900 bg-white border border-gray-300 rounded hover:bg-gray-100 focus:ring-4 focus:ring-primary-300 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 transition duration-200 ease"
disabled="">
Next
</button>
{% endif %} {% endif %}
> </div>
Next </div>
</button>
</div>
</div> </div>

View File

@ -0,0 +1,21 @@
function addBtnEvent() {
const swapButton = document.getElementById("swapPanes");
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
if (!swapButton) {
console.log("Can't find the button!");
return;
}
swapButton.addEventListener("click", () => {
console.log("Swap!");
masterPane.classList.remove("hidden");
detailPane.classList.add("hidden");
});
}
document.addEventListener("htmx:afterSettle", () => {
addBtnEvent();
});
document.addEventListener("DOMContentLoaded", () => {
addBtnEvent();
});

View File

@ -1,6 +1,6 @@
<div <div
id="drawer-update-client-{{ client.id }}" id="drawer-update-client-{{ client.id }}"
class="fixed top-0 right-0 z-40 w-full h-screen max-w-xs p-4 overflow-y-auto transition-transform translate-x-full bg-white dark:bg-gray-800" class="fixed top-0 right-0 z-50 w-full h-screen max-w-xs p-4 overflow-y-auto transition-transform translate-x-full bg-white dark:bg-gray-800"
tabindex="-1" tabindex="-1"
aria-labelledby="drawer-label-{{ client.id }}" aria-labelledby="drawer-label-{{ client.id }}"
aria-hidden="true" aria-hidden="true"

View File

@ -109,5 +109,3 @@
{% include '/secrets/partials/tree_event.js' %} {% include '/secrets/partials/tree_event.js' %}
</script> </script>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,27 @@
function addBtnEvent() {
const swapButton = document.getElementById("swapPanes");
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
if (!swapButton) {
console.log("Can't find the button!");
return;
}
swapButton.addEventListener("click", () => {
console.log("Swap!");
masterPane.classList.remove("hidden");
detailPane.classList.add("hidden");
});
}
document.addEventListener("DOMContentLoaded", () => {
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
masterPane.classList.add("hidden");
detailPane.classList.remove("hidden");
addBtnEvent();
});
document.addEventListener("htmx:afterSettle", () => {
addBtnEvent();
});

View File

@ -1,4 +1,5 @@
<div class="w-full dark:text-white"> <div class="w-full dark:text-white">
<sl-details summary="Create secret"> <sl-details summary="Create secret">
<form <form
hx-post="/secrets/create/root" hx-post="/secrets/create/root"
@ -49,5 +50,4 @@
</button> </button>
</form> </form>
</sl-details> </sl-details>
</div> </div>

View File

@ -55,6 +55,14 @@ function setGroupBreadcrumbs(name, path, secret = null) {
} }
} }
function toggleDetails() {
const masterPane = document.getElementById("master-pane");
const detailPane = document.getElementById("detail-pane");
masterPane.classList.toggle("hidden");
detailPane.classList.toggle("hidden");
}
function addTreeListener() { function addTreeListener() {
const tree = document.querySelector("sl-tree"); const tree = document.querySelector("sl-tree");
@ -83,11 +91,18 @@ function addTreeListener() {
} }
if (url) { if (url) {
htmx.ajax("GET", url, { htmx
target: "#secretdetails", .ajax("GET", url, {
swap: "OuterHTML", target: "#secretdetails",
indicator: ".secret-spinner", swap: "OuterHTML",
}); indicator: ".secret-spinner",
})
.then(() => {
toggleDetails();
selectedEl.addEventListener("click", () => {
toggleDetails();
});
});
} }
}); });
} }

View File

@ -96,6 +96,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
"clients": clients, "clients": clients,
"breadcrumbs": breadcrumbs, "breadcrumbs": breadcrumbs,
"root_group_page": True, "root_group_page": True,
"mobile_show_details": True,
} }
headers: dict[str, str] = {} headers: dict[str, str] = {}
if request.headers.get("HX-Request"): if request.headers.get("HX-Request"):
@ -144,6 +145,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
"group": group, "group": group,
"clients": clients, "clients": clients,
"breadcrumbs": breadcrumbs, "breadcrumbs": breadcrumbs,
"mobile_show_details": True,
} }
if request.headers.get("HX-Request"): if request.headers.get("HX-Request"):
# This is a HTMX request. # This is a HTMX request.
@ -187,6 +189,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
"flat_groups": flat_groups, "flat_groups": flat_groups,
"events": events, "events": events,
"secret_page": True, "secret_page": True,
"mobile_show_details": True,
} }
headers: dict[str, str] = {} headers: dict[str, str] = {}

View File

@ -403,6 +403,9 @@
.col-span-full { .col-span-full {
grid-column: 1 / -1; grid-column: 1 / -1;
} }
.clear-both {
clear: both;
}
.container { .container {
width: 100%; width: 100%;
@media (width >= 40rem) { @media (width >= 40rem) {
@ -694,6 +697,9 @@
.h-\[36rem\] { .h-\[36rem\] {
height: 36rem; height: 36rem;
} }
.h-\[calc\(100vh-2\.5rem\)\] {
height: calc(100vh - 2.5rem);
}
.h-\[calc\(100vh-2rem\)\] { .h-\[calc\(100vh-2rem\)\] {
height: calc(100vh - 2rem); height: calc(100vh - 2rem);
} }
@ -703,9 +709,15 @@
.h-\[calc\(100vh-3rem\)\] { .h-\[calc\(100vh-3rem\)\] {
height: calc(100vh - 3rem); height: calc(100vh - 3rem);
} }
.h-\[calc\(100vh-4\.5rem\)\] {
height: calc(100vh - 4.5rem);
}
.h-\[calc\(100vh-4rem\)\] { .h-\[calc\(100vh-4rem\)\] {
height: calc(100vh - 4rem); height: calc(100vh - 4rem);
} }
.h-\[calc\(100vh-5\.5rem\)\] {
height: calc(100vh - 5.5rem);
}
.h-\[calc\(100vh-6rem\)\] { .h-\[calc\(100vh-6rem\)\] {
height: calc(100vh - 6rem); height: calc(100vh - 6rem);
} }
@ -2876,6 +2888,11 @@
display: none; display: none;
} }
} }
.md\:h-\[calc\(100vh-3\.5rem\)\] {
@media (width >= 48rem) {
height: calc(100vh - 3.5rem);
}
}
.md\:h-auto { .md\:h-auto {
@media (width >= 48rem) { @media (width >= 48rem) {
height: auto; height: auto;
@ -3131,6 +3148,11 @@
height: 24rem; height: 24rem;
} }
} }
.lg\:h-\[calc\(100vh-3\.5rem\)\] {
@media (width >= 64rem) {
height: calc(100vh - 3.5rem);
}
}
.lg\:max-h-\[60rem\] { .lg\:max-h-\[60rem\] {
@media (width >= 64rem) { @media (width >= 64rem) {
max-height: 60rem; max-height: 60rem;
@ -3146,6 +3168,11 @@
width: calc(var(--spacing) * 64); width: calc(var(--spacing) * 64);
} }
} }
.lg\:w-80 {
@media (width >= 64rem) {
width: calc(var(--spacing) * 80);
}
}
.lg\:w-96 { .lg\:w-96 {
@media (width >= 64rem) { @media (width >= 64rem) {
width: calc(var(--spacing) * 96); width: calc(var(--spacing) * 96);