web: replace dialog with Popover API and CSS anchor positioning
diff --git a/AGENTS.md b/AGENTS.md
index db93f94..f96ed9b 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -52,6 +52,7 @@ tests/
- **Subtasks are tasks**: `parent_id` on tasks — subtasks get full task capabilities.
- **Tags**: Free-form labels on tasks via a many-to-many join table (`task_tags`). Used for cross-cutting concerns like `web`, `cli`, `infra`. Filter tasks by tag with `--tag`.
- **No compile-time checked queries**: Using `sqlx::query_as` with runtime binding, not `query_as!` macros. No need for `DATABASE_URL` at build time.
+- **Web UI browser targets**: Latest Firefox and Safari. Modern APIs (Popover, CSS anchor positioning) are fair game.
## Testing
diff --git a/src/bin/ranger/commands/serve.rs b/src/bin/ranger/commands/serve.rs
index 9f19616..22faf85 100644
--- a/src/bin/ranger/commands/serve.rs
+++ b/src/bin/ranger/commands/serve.rs
@@ -284,11 +284,11 @@ async fn render_board(
"ranger" span.sep { "›" }
@if backlog_names.len() > 1 {
span.backlog-picker {
- button.backlog-trigger onclick="document.getElementById('backlog-dialog').show()" {
+ button.backlog-trigger popovertarget="backlog-menu" {
(backlog_name)
span.backlog-caret { "▾" }
}
- dialog #backlog-dialog {
+ div #backlog-menu.backlog-popover popover="" {
ul.backlog-list {
@for name in &backlog_names {
li {
diff --git a/static/board.js b/static/board.js
index dd28400..298d601 100644
--- a/static/board.js
+++ b/static/board.js
@@ -1,12 +1,4 @@
(function() {
- // === Backlog popover ===
- document.addEventListener('click', function(e) {
- var dialog = document.getElementById('backlog-dialog');
- if (dialog && dialog.open && !dialog.contains(e.target) && !e.target.closest('.backlog-trigger')) {
- dialog.close();
- }
- });
-
// === Keyboard navigation ===
function getFocusables() {
return Array.from(document.querySelectorAll(
diff --git a/static/style.css b/static/style.css
index 67aebcc..6e06de3 100644
--- a/static/style.css
+++ b/static/style.css
@@ -130,7 +130,11 @@ header h1 .sep {
}
/* === Backlog popover === */
-dialog {
+.backlog-trigger {
+ anchor-name: --backlog-trigger;
+}
+
+.backlog-popover {
border: none;
border-radius: 6px;
padding: 0;
@@ -138,25 +142,14 @@ dialog {
color: var(--color-text);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
min-width: 180px;
+ inset: unset;
margin: 0;
- position: absolute;
- top: 100%;
- left: 0;
+ position-anchor: --backlog-trigger;
+ top: anchor(bottom);
+ left: anchor(left);
margin-top: 6px;
}
-dialog::backdrop {
- background: transparent;
-}
-
-dialog[open] {
- display: block;
-}
-
-.dialog-header {
- display: none;
-}
-
.backlog-list {
list-style: none;
padding: 4px;