diff --git a/pgml-dashboard/.editorconfig b/pgml-dashboard/.editorconfig new file mode 100644 index 000000000..8b67e0f71 --- /dev/null +++ b/pgml-dashboard/.editorconfig @@ -0,0 +1,16 @@ + +[*.scss] +indent_style = space +indent_size = 4 + +[*.js] +indent_style = space +indent_size = 2 + +[*.rs] +indent_style = space +indent_size = 4 + +[*.html] +ident_style = space +indent_size = 4 diff --git a/pgml-dashboard/src/components/dropdown/dropdown.scss b/pgml-dashboard/src/components/dropdown/dropdown.scss new file mode 100644 index 000000000..6b452ec33 --- /dev/null +++ b/pgml-dashboard/src/components/dropdown/dropdown.scss @@ -0,0 +1,112 @@ +.dropdown { + @extend .d-flex; + min-width: 100%; + + .dropdown-toggle { + a { + padding: 8px 12px; + } + + &:hover { + cursor: pointer; + } + + &:after { + content: none; + } + } + + .dropdown-menu { + width: 100%; + } + + &.expandable { + .dropdown-menu { + width: auto; + min-width: 100%; + } + } + + .dropdown-item { + overflow: hidden; + text-overflow: ellipsis; + } +} + +.btn-dropdown { + border-radius: $border-radius; + background: #{$gray-700}; + color: #{$gray-100}; + display: flex; + justify-content: space-between; + font-weight: $font-weight-normal; + + --bs-btn-border-color: transparent; + --bs-btn-border-width: 1px; + --bs-btn-hover-border-color: #{$neon-shade-100}; + --bs-btn-active-border-color: #{$neon-shade-100}; + --bs-btn-active-bg: #{$gray-700}; + --bs-btn-active-color: #{$gray-100}; + --bs-btn-hover-color: #{$gray-100}; + + .material-symbols-outlined { + color: #{$neon-shade-100}; + } + + &:after { + content: None; + } + + &.show { + .material-symbols-outlined { + transform: rotate(-180deg); + } + } + + .collapase { + width: 100%; + } + + .btn-dropdown-text { + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + } + + .menu-item { + a { + padding: 8px 12px; + overflow: hidden; + text-overflow: ellipsis; + } + + &:hover { + cursor: pointer; + } + + &:after { + content: None; + } + } +} + +@mixin dropdown-menu($primary-color: null) { + padding: 20px 0px 40px 0px; + overflow-y: auto; + + @if ($primary-color) { + background-color: #{$primary-color}; + } +} + +.dropdown-menu { + @include dropdown-menu($gray-600); + max-height: $dropdown-menu-height; + overflow: hidden; +} + +.sub-menu-dropdown { + @include dropdown-menu(); + border-radius: 0px; + box-shadow: 1px 1px 8px 0px rgba(0, 0, 0, 0.30); +} diff --git a/pgml-dashboard/src/components/dropdown/mod.rs b/pgml-dashboard/src/components/dropdown/mod.rs new file mode 100644 index 000000000..87835ca3c --- /dev/null +++ b/pgml-dashboard/src/components/dropdown/mod.rs @@ -0,0 +1,102 @@ +use crate::components::component; +use crate::components::component::Component; +use sailfish::TemplateOnce; + +use crate::components::StaticNavLink; + +pub enum DropdownValue { + Icon(Component), + Text(Component), +} + +impl Default for DropdownValue { + fn default() -> Self { + DropdownValue::Text("Menu".into()) + } +} + +#[derive(TemplateOnce, Default)] +#[template(path = "dropdown/template.html")] +pub struct Dropdown { + /// The currently selected value. + value: DropdownValue, + + /// The list of dropdown links to render. + links: Vec, + + /// Position of the dropdown menu. + offset: String, + + /// Whether or not the dropdown is collapsble. + collapsable: bool, + offset_collapsed: String, + + /// Where the dropdown menu should appear + menu_position: String, + expandable: bool, +} + +impl Dropdown { + pub fn new(links: Vec) -> Self { + let binding = links + .iter() + .filter(|link| link.active) + .collect::>(); + let active = binding.first(); + let value = if let Some(active) = active { + active.name.to_owned() + } else { + "Menu".to_owned() + }; + Dropdown { + links, + value: DropdownValue::Text(value.into()), + offset: "0, 10".to_owned(), + offset_collapsed: "68, -44".to_owned(), + menu_position: "".to_owned(), + ..Default::default() + } + } + + pub fn text(mut self, value: Component) -> Self { + self.value = DropdownValue::Text(value); + self + } + + pub fn icon(mut self, icon: Component) -> Self { + self.value = DropdownValue::Icon(icon); + self + } + + pub fn collapsable(mut self) -> Self { + self.collapsable = true; + self + } + + pub fn menu_end(mut self) -> Self { + self.menu_position = "dropdown-menu-end".to_owned(); + self + } + + pub fn menu_start(mut self) -> Self { + self.menu_position = "dropdown-menu-start".to_owned(); + self + } + + pub fn offset(mut self, offset: &str) -> Self { + self.offset = offset.to_owned(); + self + } + + pub fn offset_collapsed(mut self, offset: &str) -> Self { + self.offset_collapsed = offset.to_owned(); + self + } + + pub fn expandable(mut self) -> Self { + self.expandable = true; + self + } +} + +component!(Dropdown); diff --git a/pgml-dashboard/src/components/dropdown/template.html b/pgml-dashboard/src/components/dropdown/template.html new file mode 100644 index 000000000..b742725f1 --- /dev/null +++ b/pgml-dashboard/src/components/dropdown/template.html @@ -0,0 +1,56 @@ + +<% use crate::components::dropdown::DropdownValue; %> + + + + diff --git a/pgml-dashboard/src/components/left_nav_web_app/left_nav_web_app.scss b/pgml-dashboard/src/components/left_nav_web_app/left_nav_web_app.scss index e69de29bb..beb4aac9e 100644 --- a/pgml-dashboard/src/components/left_nav_web_app/left_nav_web_app.scss +++ b/pgml-dashboard/src/components/left_nav_web_app/left_nav_web_app.scss @@ -0,0 +1,12 @@ +.leftnav { + @extend .navbar; + max-width: 260px; + + border: none; + align-items: start; + background-color: inherit; + + @include media-breakpoint-down(lg) { + background-color: #{$gray-900} + } +} diff --git a/pgml-dashboard/src/components/left_nav_web_app/template.html b/pgml-dashboard/src/components/left_nav_web_app/template.html index c2713ba37..881db504d 100644 --- a/pgml-dashboard/src/components/left_nav_web_app/template.html +++ b/pgml-dashboard/src/components/left_nav_web_app/template.html @@ -1,4 +1,4 @@ -<% use crate::components::LeftNavMenu; %> +<% use crate::components::{LeftNavMenu, Dropdown}; %>