This commit is contained in:
@@ -262,6 +262,33 @@
|
||||
});
|
||||
}
|
||||
window.devicesPageSize = devicesPageSize;
|
||||
|
||||
// The devices table lives inside an `overflow-x-auto` wrapper so wide
|
||||
// column sets get a horizontal scrollbar instead of pushing the page
|
||||
// out. CSS forces overflow-y to auto on the same axis, which would
|
||||
// clip the per-row action popover (a `<details>` > `<div>` inside a
|
||||
// <td>). On toggle we flip the popover to `position: fixed` and pin
|
||||
// it to the summary's viewport rect so it escapes the scroll context.
|
||||
// Inline `ontoggle=` is preserved across htmx swaps without re-binding.
|
||||
function actionMenuToggle(details) {
|
||||
const popover = details.querySelector('[data-action-menu]');
|
||||
if (!popover) return;
|
||||
if (!details.open) {
|
||||
popover.style.position = '';
|
||||
popover.style.top = '';
|
||||
popover.style.left = '';
|
||||
popover.style.right = '';
|
||||
return;
|
||||
}
|
||||
const summary = details.querySelector('summary');
|
||||
if (!summary) return;
|
||||
const rect = summary.getBoundingClientRect();
|
||||
popover.style.position = 'fixed';
|
||||
popover.style.top = rect.bottom + 4 + 'px';
|
||||
popover.style.right = (window.innerWidth - rect.right - 8) + 'px';
|
||||
popover.style.left = 'auto';
|
||||
}
|
||||
window.actionMenuToggle = actionMenuToggle;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -562,12 +562,14 @@ async fn render_table(
|
||||
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
||||
let now = chrono::Utc::now();
|
||||
let mut s = String::new();
|
||||
// No `overflow-hidden` on the table wrapper: the per-row action menu is
|
||||
// an absolutely-positioned `<details>` popover inside a <td>, and the
|
||||
// wrapper's clipping was hiding the bottom half of the menu.
|
||||
// `overflow-x-auto` on the inner wrapper gives the wide table a
|
||||
// horizontal scrollbar instead of pushing past the viewport. The
|
||||
// action-menu popover compensates for the implicit `overflow-y: auto`
|
||||
// (CSS spec) by switching to `position: fixed` on toggle — see
|
||||
// `actionMenuToggle` in admin_ui/index.html.
|
||||
let _ = write!(
|
||||
s,
|
||||
r##"<div class="rounded-md border border-slate-800 bg-slate-900">
|
||||
r##"<div class="rounded-md border border-slate-800 bg-slate-900 overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="text-xs uppercase text-slate-500 bg-slate-950">
|
||||
<tr>
|
||||
@@ -1065,9 +1067,9 @@ fn render_device_row(
|
||||
s,
|
||||
r##"
|
||||
<td class="px-3 py-2">
|
||||
<details class="text-right relative">
|
||||
<details class="text-right relative" ontoggle="actionMenuToggle(this)">
|
||||
<summary class="cursor-pointer list-none text-xs text-slate-400 hover:text-slate-200 select-none">···</summary>
|
||||
<div class="absolute right-2 mt-1 z-10 w-56 bg-slate-900 border border-slate-700 rounded shadow-lg p-2 space-y-1 text-left">
|
||||
<div data-action-menu class="absolute right-2 mt-1 z-50 w-56 bg-slate-900 border border-slate-700 rounded shadow-lg p-2 space-y-1 text-left">
|
||||
<a class="block w-full text-left px-2 py-1 text-xs text-sky-300 hover:bg-sky-900/40 rounded"
|
||||
href="/admin/connect/{id}" target="_blank" rel="noopener"
|
||||
data-confirm="{confirm_connect}"
|
||||
|
||||
@@ -856,12 +856,14 @@ async fn render_table(
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let mut s = String::new();
|
||||
// No `overflow-hidden` on the table wrapper: the per-row action menu is
|
||||
// an absolutely-positioned `<details>` popover inside a <td>, and the
|
||||
// wrapper's clipping was hiding the bottom half of the menu.
|
||||
// `overflow-x-auto` on the inner wrapper gives the wide table a
|
||||
// horizontal scrollbar instead of pushing past the viewport. The
|
||||
// action-menu popover compensates for the implicit `overflow-y: auto`
|
||||
// (CSS spec) by switching to `position: fixed` on toggle — see
|
||||
// `actionMenuToggle` in admin_ui/index.html.
|
||||
let _ = write!(
|
||||
s,
|
||||
r##"<div class="rounded-md border border-slate-800 bg-slate-900">
|
||||
r##"<div class="rounded-md border border-slate-800 bg-slate-900 overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="text-xs uppercase text-slate-500 bg-slate-950">
|
||||
<tr>
|
||||
@@ -1190,9 +1192,9 @@ fn render_user_row(
|
||||
s,
|
||||
r##"
|
||||
<td class="px-3 py-2">
|
||||
<details class="text-right relative">
|
||||
<details class="text-right relative" ontoggle="actionMenuToggle(this)">
|
||||
<summary class="cursor-pointer list-none text-xs text-slate-400 hover:text-slate-200 select-none">···</summary>
|
||||
<div class="absolute right-2 mt-1 z-10 w-64 bg-slate-900 border border-slate-700 rounded shadow-lg p-2 space-y-1 text-left">
|
||||
<div data-action-menu class="absolute right-2 mt-1 z-50 w-64 bg-slate-900 border border-slate-700 rounded shadow-lg p-2 space-y-1 text-left">
|
||||
<form class="space-y-1" hx-post="/admin/pages/users/{id}/update-info?page={page}{q_param}" hx-target="#users-region" hx-swap="innerHTML">
|
||||
<input name="display_name" value="{display_name}" placeholder="{ph_dn}" class="w-full bg-slate-800 border border-slate-700 rounded px-2 py-1 text-xs"/>
|
||||
<input name="email" type="email" value="{email}" placeholder="{ph_email}" class="w-full bg-slate-800 border border-slate-700 rounded px-2 py-1 text-xs"/>
|
||||
|
||||
Reference in New Issue
Block a user