all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [PATCH datacenter-manager/yew-comp/yew-widget-toolkit 0/3] minor ui/ux tweaks for pwt and yew-comp
@ 2026-05-06  9:55 Shannon Sterz
  2026-05-06  9:55 ` [PATCH yew-widget-toolkit 1/3] dropdown/align: make the picker render above or below a dropdown Shannon Sterz
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Shannon Sterz @ 2026-05-06  9:55 UTC (permalink / raw)
  To: yew-devel

this series includes two minor tweaks that should improve the usability and
user experience of some yew components.

dropdowns should now render their pickers below or above the component
depending on the size of the picker and available screen space. a dropup mode
improves usability for filter fields when the picker is rendered above the
dropdown.

the log view in the syslog and task log components was slightly tweaked to avoid
interference between scrollbars and drag handles.

changes since the rfc:

- drop the approach based on css classes and pass the information on `dropup`
  mode in the `DropdownController` instead (thanks @ Dominik Csapak)


pwt:

Shannon Sterz (1):
  dropdown/align: make the picker render above or below a dropdown

 src/dom/align.rs            |  6 +++-
 src/widget/dropdown.rs      | 69 +++++++++++++++++++++++++++++++------
 src/widget/form/combobox.rs |  3 +-
 src/widget/grid_picker.rs   | 20 +++++++++--
 4 files changed, 84 insertions(+), 14 deletions(-)


yew-comp:

Shannon Sterz (1):
  task_viewer/syslog: make padding margin to improve ux

 src/syslog.rs      | 2 +-
 src/task_viewer.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)


datacenter-manager:

Shannon Sterz (1):
  Revert "ui: css: limit max-height of dropdown picker"

 ui/css/desktop-yew-style.scss | 6 ------
 1 file changed, 6 deletions(-)


Summary over all repositories:
  7 files changed, 86 insertions(+), 22 deletions(-)

-- 
Generated by murpp 0.10.0




^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH yew-widget-toolkit 1/3] dropdown/align: make the picker render above or below a dropdown
  2026-05-06  9:55 [PATCH datacenter-manager/yew-comp/yew-widget-toolkit 0/3] minor ui/ux tweaks for pwt and yew-comp Shannon Sterz
@ 2026-05-06  9:55 ` Shannon Sterz
  2026-05-06  9:55 ` [PATCH yew-comp 2/3] task_viewer/syslog: make padding margin to improve ux Shannon Sterz
  2026-05-06  9:55 ` [PATCH datacenter-manager 3/3] Revert "ui: css: limit max-height of dropdown picker" Shannon Sterz
  2 siblings, 0 replies; 4+ messages in thread
From: Shannon Sterz @ 2026-05-06  9:55 UTC (permalink / raw)
  To: yew-devel

and detect dropup mode. this allows better ux restricting the height
of the picker to the maximum of the space below or above a `Dropdown`.
the `DropdownController` is also extended to include whether the
picker should be rendered in `dropup` mode, meaning that it is
actually being rendered above the `Dropdown` component.

the `GridPicker` and `Combobox` components are extended to take
advantage of the new "dropup` mode. allowing the picker to be rendered
in reverse order, so that the filter box is rendered right next to the
`Dropdown` input field in dropup mode. reversing the flex column
direction here is preferable over changing the markup, as the filter
input field should still semantically be the first element in the
picker. it also has better behaviour in terms of scrolling, as the
filter input field would be otherwise scrolled out of view by default.

this implements the fix outlined in [1].

[1]:
https://git.proxmox.com/?p=proxmox-datacenter-manager.git;a=commit;f=ui/css/desktop-yew-style.scss;h=dafa21a3

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 src/dom/align.rs            |  6 +++-
 src/widget/dropdown.rs      | 69 +++++++++++++++++++++++++++++++------
 src/widget/form/combobox.rs |  3 +-
 src/widget/grid_picker.rs   | 20 +++++++++--
 4 files changed, 84 insertions(+), 14 deletions(-)

diff --git a/src/dom/align.rs b/src/dom/align.rs
index 603a5b8d..a20cc6ed 100644
--- a/src/dom/align.rs
+++ b/src/dom/align.rs
@@ -456,7 +456,11 @@ where
         style.remove_property("overflow")?;
     }
     let padding = 2.0 * options.viewport_padding;
-    style.set_property("max-height", &format!("calc(100dvh - {padding}px)"))?;
+
+    if style.get_property_value("max-height")? == "" {
+        style.set_property("max-height", &format!("calc(100dvh - {padding}px)"))?;
+    }
+
     style.set_property("max-width", &format!("calc(100dvw - {padding}px)"))?;
 
     if options.align_width {
diff --git a/src/widget/dropdown.rs b/src/widget/dropdown.rs
index 1af09633..023a4928 100644
--- a/src/widget/dropdown.rs
+++ b/src/widget/dropdown.rs
@@ -1,7 +1,11 @@
+use std::cmp;
+
 use html::Scope;
 use wasm_bindgen::JsCast;
 use web_sys::HtmlInputElement;
 
+use crate::dom::IntoHtmlElement;
+
 use yew::html::{IntoEventCallback, IntoPropValue};
 use yew::prelude::*;
 
@@ -19,6 +23,7 @@ use crate::dom::focus::{FocusTracker, element_is_focusable, get_first_focusable}
 #[derive(Clone)]
 pub struct DropdownController {
     link: Scope<PwtDropdown>,
+    dropup: bool,
 }
 
 impl DropdownController {
@@ -34,6 +39,12 @@ impl DropdownController {
             controller.change_value(key.to_string());
         })
     }
+
+    /// Whether the picker should be rendered in "dropup" mode, meaning it is being rendered above
+    /// the [Dropdown].
+    pub fn dropup(&self) -> bool {
+        self.dropup
+    }
 }
 /// Base widget to implement [Combobox](crate::widget::form::Combobox) like widgets.
 ///
@@ -155,15 +166,18 @@ impl PwtDropdown {
     }
 
     fn update_picker_placer(&mut self, _props: &Dropdown) {
-        let align_options = _props.align_options.clone().unwrap_or(
-            AlignOptions::new(
-                Point::BottomStart,
-                Point::TopStart,
-                GrowDirection::TopBottom,
-            )
-            .viewport_padding(5.0)
-            .align_width(true),
-        );
+        let align_options =
+            AlignOptions::new(Point::BottomStart, Point::TopStart, GrowDirection::None)
+                .viewport_padding(5.0)
+                .align_width(true)
+                .with_fallback_placement(Point::TopStart, Point::BottomStart, GrowDirection::None)
+                .with_fallback_placement(
+                    Point::BottomStart,
+                    Point::TopStart,
+                    GrowDirection::TopBottom,
+                );
+
+        let align_options = _props.align_options.clone().unwrap_or(align_options);
         self.picker_placer = match AutoFloatingPlacement::new(
             self.dropdown_ref.clone(),
             self.picker_ref.clone(),
@@ -337,8 +351,44 @@ impl Component for PwtDropdown {
             Msg::Input(input.value())
         });
 
+        // intentionally fail silently here; if any of these values aren't available, falling
+        // back to the default logic is fine, this should just provide improved ui/ux.
+        let dropdown_rect = self
+            .dropdown_ref
+            .clone()
+            .into_html_element()
+            .map(|e| e.get_bounding_client_rect());
+
+        let window_height = web_sys::window()
+            .and_then(|w| w.inner_height().ok())
+            .and_then(|h| h.as_f64().map(|h| h as i64));
+
+        let mut dropup = false;
+
+        if let Some(dropdown_rect) = dropdown_rect
+            && let Some(window_height) = window_height
+        {
+            let top = dropdown_rect.y() as i64;
+            let bottom = window_height - (top + (dropdown_rect.height() as i64));
+            let height = cmp::max(top, bottom) - 5;
+
+            if let Some(picker) = self.picker_ref.clone().into_html_element() {
+                let _ = picker
+                    .style()
+                    .set_property("max-height", &format!("{height}px"))
+                    .ok();
+
+                let height = picker.get_bounding_client_rect().height() as i64;
+
+                if height > bottom && height <= top {
+                    dropup = true
+                }
+            }
+        }
+
         let controller = DropdownController {
             link: ctx.link().clone(),
+            dropup,
         };
 
         let data_show = self.show.then_some("true");
@@ -497,7 +547,6 @@ impl Component for PwtDropdown {
     fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
         if first_render {
             let props = ctx.props();
-
             self.update_picker_placer(props);
 
             if props.input_props.autofocus {
diff --git a/src/widget/form/combobox.rs b/src/widget/form/combobox.rs
index 40466280..46afc82a 100644
--- a/src/widget/form/combobox.rs
+++ b/src/widget/form/combobox.rs
@@ -321,7 +321,8 @@ impl Component for PwtCombobox {
                 .show_filter(show_filter)
                 .filter(filter.clone())
                 .autoselect_filter(auto_select_filter)
-                .on_select(args.controller.on_select_callback());
+                .on_select(args.controller.on_select_callback())
+                .filter_below(args.controller.dropup());
 
             if show_filter {
                 picker.set_on_filter_change({
diff --git a/src/widget/grid_picker.rs b/src/widget/grid_picker.rs
index 304e54a2..30772733 100644
--- a/src/widget/grid_picker.rs
+++ b/src/widget/grid_picker.rs
@@ -8,10 +8,11 @@ use yew::html::{IntoEventCallback, IntoPropValue};
 use yew::prelude::*;
 use yew::virtual_dom::{Key, VComp, VNode};
 
+use crate::css::{Display, FlexDirection};
 use crate::props::{FilterFn, IntoTextFilterFn, TextFilterFn};
 use crate::state::{DataStore, Selection};
 use crate::widget::data_table::DataTable;
-use crate::widget::{Column, Input, Row};
+use crate::widget::{Container, Input, Row};
 use crate::{impl_yew_std_props_builder, prelude::*};
 
 use pwt_macros::builder;
@@ -79,6 +80,13 @@ pub struct GridPicker<S: DataStore> {
     #[builder(IntoPropValue, into_prop_value)]
     #[prop_or_default]
     pub autoselect_filter: Option<bool>,
+
+    /// Whether to render the filter above or below the table. Useful when used in a
+    /// [Dropdown](crate::widget::Dropdown) where the picker could appear above or below the
+    /// dropdown's input field.
+    #[builder(IntoPropValue, into_prop_value)]
+    #[prop_or_default]
+    pub filter_below: Option<bool>,
 }
 
 impl<S: DataStore> GridPicker<S> {
@@ -185,7 +193,15 @@ impl<S: DataStore + 'static> Component for PwtGridPicker<S> {
             .selection(self.selection.clone())
             .into();
 
-        let mut view = Column::new().class("pwt-flex-fill pwt-overflow-auto");
+        let mut view = Container::new()
+            .class(Display::Flex)
+            .class("pwt-flex-fill pwt-overflow-auto");
+
+        view = if props.filter_below == Some(true) {
+            view.class(FlexDirection::ColumnReverse)
+        } else {
+            view.class(FlexDirection::Column)
+        };
 
         let show_filter = props
             .show_filter
-- 
2.47.3





^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH yew-comp 2/3] task_viewer/syslog: make padding margin to improve ux
  2026-05-06  9:55 [PATCH datacenter-manager/yew-comp/yew-widget-toolkit 0/3] minor ui/ux tweaks for pwt and yew-comp Shannon Sterz
  2026-05-06  9:55 ` [PATCH yew-widget-toolkit 1/3] dropdown/align: make the picker render above or below a dropdown Shannon Sterz
@ 2026-05-06  9:55 ` Shannon Sterz
  2026-05-06  9:55 ` [PATCH datacenter-manager 3/3] Revert "ui: css: limit max-height of dropdown picker" Shannon Sterz
  2 siblings, 0 replies; 4+ messages in thread
From: Shannon Sterz @ 2026-05-06  9:55 UTC (permalink / raw)
  To: yew-devel

previously, using padding here meant that potential scrolbars would
overlap with the resize handles. by switching to margin the scrolbars
overlap the content of the `LogView` instead. improving usability by
no longer having interference between the scrollbars and the drag
handles.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 src/syslog.rs      | 2 +-
 src/task_viewer.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/syslog.rs b/src/syslog.rs
index 03926d1..d034f80 100644
--- a/src/syslog.rs
+++ b/src/syslog.rs
@@ -173,7 +173,7 @@ impl ProxmoxSyslog {
                 .into()
         } else {
             LogView::new(props.base_url.clone())
-                .padding(2)
+                .margin(2)
                 .class("pwt-flex-fill")
                 .service(props.service.clone())
                 .since(date_time_to_epoch(&self.since, &self.since_time))
diff --git a/src/task_viewer.rs b/src/task_viewer.rs
index e78454e..648d20b 100644
--- a/src/task_viewer.rs
+++ b/src/task_viewer.rs
@@ -290,7 +290,7 @@ impl PwtTaskViewer {
             .with_child(toolbar)
             .with_child(
                 LogView::new(url)
-                    .padding(2)
+                    .margin(2)
                     .class("pwt-flex-fill")
                     .active(active),
             )
-- 
2.47.3





^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH datacenter-manager 3/3] Revert "ui: css: limit max-height of dropdown picker"
  2026-05-06  9:55 [PATCH datacenter-manager/yew-comp/yew-widget-toolkit 0/3] minor ui/ux tweaks for pwt and yew-comp Shannon Sterz
  2026-05-06  9:55 ` [PATCH yew-widget-toolkit 1/3] dropdown/align: make the picker render above or below a dropdown Shannon Sterz
  2026-05-06  9:55 ` [PATCH yew-comp 2/3] task_viewer/syslog: make padding margin to improve ux Shannon Sterz
@ 2026-05-06  9:55 ` Shannon Sterz
  2 siblings, 0 replies; 4+ messages in thread
From: Shannon Sterz @ 2026-05-06  9:55 UTC (permalink / raw)
  To: yew-devel

This reverts commit dafa21a31fb0a178c1ca9910ca266d2b221076b9.

the fix outline in this commit is now implement in
proxmox-widget-toolkit, so this stop-gap fix is no longer needed.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 ui/css/desktop-yew-style.scss | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/ui/css/desktop-yew-style.scss b/ui/css/desktop-yew-style.scss
index b41a046..f09ed61 100644
--- a/ui/css/desktop-yew-style.scss
+++ b/ui/css/desktop-yew-style.scss
@@ -15,9 +15,3 @@
         @include elevation-box-shadow(1);
     }
 }
-
-// TODO: move to pwt assets once we're sure about doing it this way or drop, if
-// we rewroked layouting and placement of the dropdown picker.
-.pwt-dropdown {
-    max-height: min(45dvh, 500px) !important;
-}
-- 
2.47.3





^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-05-06  9:56 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06  9:55 [PATCH datacenter-manager/yew-comp/yew-widget-toolkit 0/3] minor ui/ux tweaks for pwt and yew-comp Shannon Sterz
2026-05-06  9:55 ` [PATCH yew-widget-toolkit 1/3] dropdown/align: make the picker render above or below a dropdown Shannon Sterz
2026-05-06  9:55 ` [PATCH yew-comp 2/3] task_viewer/syslog: make padding margin to improve ux Shannon Sterz
2026-05-06  9:55 ` [PATCH datacenter-manager 3/3] Revert "ui: css: limit max-height of dropdown picker" Shannon Sterz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal