diff --git a/src/base/component.rs b/src/base/component.rs index 4edfc9a..4df64ff 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -1,53 +1,5 @@ //! Componentes nativos proporcionados por PageTop. -use crate::AutoDefault; - -use std::fmt; - -// **< FontSize >*********************************************************************************** - -#[derive(AutoDefault)] -pub enum FontSize { - ExtraLarge, - XxLarge, - XLarge, - Large, - Medium, - #[default] - Normal, - Small, - XSmall, - XxSmall, - ExtraSmall, -} - -#[rustfmt::skip] -impl FontSize { - #[inline] - pub const fn as_str(&self) -> &'static str { - match self { - FontSize::ExtraLarge => "fs__x3l", - FontSize::XxLarge => "fs__x2l", - FontSize::XLarge => "fs__xl", - FontSize::Large => "fs__l", - FontSize::Medium => "fs__m", - FontSize::Normal => "", - FontSize::Small => "fs__s", - FontSize::XSmall => "fs__xs", - FontSize::XxSmall => "fs__x2s", - FontSize::ExtraSmall => "fs__x3s", - } - } -} - -impl fmt::Display for FontSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -// ************************************************************************************************* - mod html; pub use html::Html; @@ -56,8 +8,3 @@ pub use block::Block; mod poweredby; pub use poweredby::PoweredBy; - -mod icon; -pub use icon::{Icon, IconKind}; - -pub mod menu; diff --git a/src/base/component/icon.rs b/src/base/component/icon.rs deleted file mode 100644 index 73e5ac4..0000000 --- a/src/base/component/icon.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::prelude::*; - -const DEFAULT_VIEWBOX: &str = "0 0 16 16"; - -#[derive(AutoDefault)] -pub enum IconKind { - #[default] - None, - Font(FontSize), - Svg { - shapes: Markup, - viewbox: AttrValue, - }, -} - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Icon { - classes : AttrClasses, - icon_kind : IconKind, - aria_label: AttrL10n, -} - -impl Component for Icon { - fn new() -> Self { - Icon::default() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - if !matches!(self.icon_kind(), IconKind::None) { - self.alter_classes(ClassesOp::Prepend, "icon"); - } - if let IconKind::Font(font_size) = self.icon_kind() { - self.alter_classes(ClassesOp::Add, font_size.as_str()); - } - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - match self.icon_kind() { - IconKind::None => PrepareMarkup::None, - IconKind::Font(_) => { - let aria_label = self.aria_label().lookup(cx); - let has_label = aria_label.is_some(); - PrepareMarkup::With(html! { - i - class=[self.classes().get()] - role=[has_label.then_some("img")] - aria-label=[aria_label] - aria-hidden=[(!has_label).then_some("true")] - {} - }) - } - IconKind::Svg { shapes, viewbox } => { - let aria_label = self.aria_label().lookup(cx); - let has_label = aria_label.is_some(); - let viewbox = viewbox.get().unwrap_or_else(|| DEFAULT_VIEWBOX.to_string()); - PrepareMarkup::With(html! { - svg - xmlns="http://www.w3.org/2000/svg" - viewBox=(viewbox) - fill="currentColor" - focusable="false" - class=[self.classes().get()] - role=[has_label.then_some("img")] - aria-label=[aria_label] - aria-hidden=[(!has_label).then_some("true")] - { - (shapes) - } - }) - } - } - } -} - -impl Icon { - pub fn font() -> Self { - Icon::default().with_icon_kind(IconKind::Font(FontSize::default())) - } - - pub fn font_sized(font_size: FontSize) -> Self { - Icon::default().with_icon_kind(IconKind::Font(font_size)) - } - - pub fn svg(shapes: Markup) -> Self { - Icon::default().with_icon_kind(IconKind::Svg { - shapes, - viewbox: AttrValue::default(), - }) - } - - pub fn svg_with_viewbox(shapes: Markup, viewbox: impl AsRef) -> Self { - Icon::default().with_icon_kind(IconKind::Svg { - shapes, - viewbox: AttrValue::new(viewbox), - }) - } - - // **< Icon BUILDER >*************************************************************************** - - /// Modifica la lista de clases CSS aplicadas al icono. - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef) -> Self { - self.classes.alter_value(op, classes); - self - } - - #[builder_fn] - pub fn with_icon_kind(mut self, icon_kind: IconKind) -> Self { - self.icon_kind = icon_kind; - self - } - - #[builder_fn] - pub fn with_aria_label(mut self, label: L10n) -> Self { - self.aria_label.alter_value(label); - self - } - - // **< Icon GETTERS >*************************************************************************** - - /// Devuelve las clases CSS asociadas al icono. - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - pub fn icon_kind(&self) -> &IconKind { - &self.icon_kind - } - - pub fn aria_label(&self) -> &AttrL10n { - &self.aria_label - } -} diff --git a/src/base/component/menu.rs b/src/base/component/menu.rs deleted file mode 100644 index 14f7589..0000000 --- a/src/base/component/menu.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod menu_menu; -pub use menu_menu::Menu; - -mod item; -pub use item::{Item, ItemKind}; - -mod submenu; -pub use submenu::Submenu; - -mod megamenu; -pub use megamenu::Megamenu; - -mod group; -pub use group::Group; - -mod element; -pub use element::{Element, ElementType}; diff --git a/src/base/component/menu/element.rs b/src/base/component/menu/element.rs deleted file mode 100644 index 6d14204..0000000 --- a/src/base/component/menu/element.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::prelude::*; - -type Content = Typed; -type SubmenuItems = Typed; - -#[derive(AutoDefault)] -pub enum ElementType { - #[default] - Void, - Html(Content), - Submenu(SubmenuItems), -} - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Element { - element_type: ElementType, -} - -impl Component for Element { - fn new() -> Self { - Element::default() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - match self.element_type() { - ElementType::Void => PrepareMarkup::None, - ElementType::Html(content) => PrepareMarkup::With(html! { - (content.render(cx)) - }), - ElementType::Submenu(submenu) => PrepareMarkup::With(html! { - (submenu.render(cx)) - }), - } - } -} - -impl Element { - pub fn html(content: Html) -> Self { - Element { - element_type: ElementType::Html(Content::with(content)), - } - } - - pub fn submenu(submenu: menu::Submenu) -> Self { - Element { - element_type: ElementType::Submenu(SubmenuItems::with(submenu)), - } - } - - // **< Element GETTERS >************************************************************************ - - pub fn element_type(&self) -> &ElementType { - &self.element_type - } -} diff --git a/src/base/component/menu/group.rs b/src/base/component/menu/group.rs deleted file mode 100644 index 41279b4..0000000 --- a/src/base/component/menu/group.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Group { - id : AttrId, - elements: Children, -} - -impl Component for Group { - fn new() -> Self { - Group::default() - } - - fn id(&self) -> Option { - self.id.get() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - div id=[self.id()] class="menu-group" { - (self.elements().render(cx)) - } - }) - } -} - -impl Group { - // **< Group BUILDER >************************************************************************** - - /// Establece el identificador único (`id`) del grupo. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); - self - } - - /// Añade un nuevo elemento al menú. - pub fn add_element(mut self, element: menu::Element) -> Self { - self.elements - .alter_typed(TypedOp::Add(Typed::with(element))); - self - } - - /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_elements(mut self, op: TypedOp) -> Self { - self.elements.alter_typed(op); - self - } - - // **< Group GETTERS >************************************************************************** - - /// Devuelve la lista de elementos (`children`) del grupo. - pub fn elements(&self) -> &Children { - &self.elements - } -} diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs deleted file mode 100644 index 07d629a..0000000 --- a/src/base/component/menu/item.rs +++ /dev/null @@ -1,183 +0,0 @@ -use crate::prelude::*; - -//use super::{Megamenu, Submenu}; - -type Label = L10n; -type Content = Typed; -type SubmenuItems = Typed; -//type MegamenuGroups = Typed; - -#[derive(AutoDefault)] -pub enum ItemKind { - #[default] - Void, - Label(Label), - Link(Label, FnPathByContext), - LinkBlank(Label, FnPathByContext), - Html(Content), - Submenu(Label, SubmenuItems), - // Megamenu(Label, MegamenuGroups), -} - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Item { - item_kind : ItemKind, - description: AttrL10n, - left_icon : Typed, - right_icon : Typed, -} - -impl Component for Item { - fn new() -> Self { - Item::default() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let description = self.description().lookup(cx); - let left_icon = self.left_icon().render(cx); - let right_icon = self.right_icon().render(cx); - - match self.item_kind() { - ItemKind::Void => PrepareMarkup::None, - ItemKind::Label(label) => PrepareMarkup::With(html! { - li class="menu__label" { - span title=[description] { - (left_icon) - (label.using(cx)) - (right_icon) - } - } - }), - ItemKind::Link(label, path) => PrepareMarkup::With(html! { - li class="menu__link" { - a href=(path(cx)) title=[description] { - (left_icon) - (label.using(cx)) - (right_icon) - } - } - }), - ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! { - li class="menu__link" { - a href=(path(cx)) title=[description] target="_blank" { - (left_icon) - (label.using(cx)) - (right_icon) - } - } - }), - ItemKind::Html(content) => PrepareMarkup::With(html! { - li class="menu__html" { - (content.render(cx)) - } - }), - ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! { - li class="menu__children" { - a href="#" title=[description] { - (left_icon) - (label.using(cx)) i class="menu__icon bi-chevron-down" {} - } - div class="menu__subs" { - (submenu.render(cx)) - } - } - }), - /* - ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! { - li class="menu__children" { - a href="#" title=[description] { - (left_icon) - (label.escaped(cx.langid())) i class="menu__icon bi-chevron-down" {} - } - div class="menu__subs menu__mega" { - (megamenu.render(cx)) - } - } - }), - */ - } - } -} - -impl Item { - pub fn label(label: L10n) -> Self { - Item { - item_kind: ItemKind::Label(label), - ..Default::default() - } - } - - pub fn link(label: L10n, path: FnPathByContext) -> Self { - Item { - item_kind: ItemKind::Link(label, path), - ..Default::default() - } - } - - pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { - Item { - item_kind: ItemKind::LinkBlank(label, path), - ..Default::default() - } - } - - pub fn html(content: Html) -> Self { - Item { - item_kind: ItemKind::Html(Content::with(content)), - ..Default::default() - } - } - - pub fn submenu(label: L10n, submenu: menu::Submenu) -> Self { - Item { - item_kind: ItemKind::Submenu(label, SubmenuItems::with(submenu)), - ..Default::default() - } - } - /* - pub fn megamenu(label: L10n, megamenu: Megamenu) -> Self { - Item { - item_kind: ItemKind::Megamenu(label, MegamenuGroups::with(megamenu)), - ..Default::default() - } - } - */ - // **< Item BUILDER >*************************************************************************** - - #[builder_fn] - pub fn with_description(mut self, text: L10n) -> Self { - self.description.alter_value(text); - self - } - - #[builder_fn] - pub fn with_left_icon>(mut self, icon: Option) -> Self { - self.left_icon.alter_component(icon.map(Into::into)); - self - } - - #[builder_fn] - pub fn with_right_icon>(mut self, icon: Option) -> Self { - self.right_icon.alter_component(icon.map(Into::into)); - self - } - - // **< Item GETTERS >*************************************************************************** - - pub fn item_kind(&self) -> &ItemKind { - &self.item_kind - } - - pub fn description(&self) -> &AttrL10n { - &self.description - } - - pub fn left_icon(&self) -> &Typed { - &self.left_icon - } - - pub fn right_icon(&self) -> &Typed { - &self.right_icon - } -} diff --git a/src/base/component/menu/megamenu.rs b/src/base/component/menu/megamenu.rs deleted file mode 100644 index f22b184..0000000 --- a/src/base/component/menu/megamenu.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Megamenu { - id : AttrId, - groups: Children, -} - -impl Component for Megamenu { - fn new() -> Self { - Megamenu::default() - } - - fn id(&self) -> Option { - self.id.get() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - div id=[self.id()] class="menu__groups" { - (self.groups().render(cx)) - } - }) - } -} - -impl Megamenu { - // **< Megamenu BUILDER >*********************************************************************** - - /// Establece el identificador único (`id`) del megamenú. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); - self - } - - /// Añade un nuevo grupo al menú. - pub fn add_group(mut self, group: menu::Group) -> Self { - self.groups.alter_typed(TypedOp::Add(Typed::with(group))); - self - } - - /// Modifica la lista de grupos (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_groups(mut self, op: TypedOp) -> Self { - self.groups.alter_typed(op); - self - } - - // **< Megamenu GETTERS >*********************************************************************** - - /// Devuelve la lista de grupos (`children`) del megamenú. - pub fn groups(&self) -> &Children { - &self.groups - } -} diff --git a/src/base/component/menu/menu_menu.rs b/src/base/component/menu/menu_menu.rs deleted file mode 100644 index a7f91be..0000000 --- a/src/base/component/menu/menu_menu.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Menu { - id : AttrId, - classes: AttrClasses, - items : Children, -} - -impl Component for Menu { - fn new() -> Self { - Menu::default() - } - - fn id(&self) -> Option { - self.id.get() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes(ClassesOp::Prepend, "menu"); - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - // cx.set_param::(PARAM_BASE_INCLUDE_MENU_ASSETS, &true); - // cx.set_param::(PARAM_BASE_INCLUDE_ICONS, &true); - - PrepareMarkup::With(html! { - div id=[self.id()] class=[self.classes().get()] { - div class="menu__wrapper" { - div class="menu__panel" { - div class="menu__overlay" {} - nav class="menu__nav" { - div class="menu__header" { - button type="button" class="menu__back" { - (Icon::svg(html! { - path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0" {} - }).render(cx)) - } - div class="menu__title" {} - button type="button" class="menu__close" { - (Icon::svg(html! { - path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z" {} - }).render(cx)) - } - } - ul class="menu__list" { - (self.items().render(cx)) - } - } - } - button - type="button" - class="menu__trigger" - title=[L10n::l("menu_toggle").lookup(cx)] - { - span {} span {} span {} - } - } - } - }) - } -} - -impl Menu { - // **< Menu BUILDER >*************************************************************************** - - /// Establece el identificador único (`id`) del menú. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); - self - } - - /// Modifica la lista de clases CSS aplicadas al menú. - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef) -> Self { - self.classes.alter_value(op, classes); - self - } - - /// Añade un nuevo ítem al menú. - pub fn add_item(mut self, item: menu::Item) -> Self { - self.items.alter_typed(TypedOp::Add(Typed::with(item))); - self - } - - /// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_items(mut self, op: TypedOp) -> Self { - self.items.alter_typed(op); - self - } - - // **< Menu GETTERS >*************************************************************************** - - /// Devuelve las clases CSS asociadas al menú. - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - /// Devuelve la lista de ítems (`children`) del menú. - pub fn items(&self) -> &Children { - &self.items - } -} diff --git a/src/base/component/menu/submenu.rs b/src/base/component/menu/submenu.rs deleted file mode 100644 index 5877052..0000000 --- a/src/base/component/menu/submenu.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Submenu { - id : AttrId, - title: AttrL10n, - items: Children, -} - -impl Component for Submenu { - fn new() -> Self { - Submenu::default() - } - - fn id(&self) -> Option { - self.id.get() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - div id=[self.id()] class="menu__items" { - @if let Some(title) = self.title().lookup(cx) { - h4 class="menu__title" { (title) } - } - ul { - (self.items().render(cx)) - } - } - }) - } -} - -impl Submenu { - // **< Submenu BUILDER >************************************************************************ - - /// Establece el identificador único (`id`) del submenú. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); - self - } - - #[builder_fn] - pub fn with_title(mut self, title: L10n) -> Self { - self.title.alter_value(title); - self - } - - /// Añade un nuevo ítem al submenú. - pub fn add_item(mut self, item: menu::Item) -> Self { - self.items.alter_typed(TypedOp::Add(Typed::with(item))); - self - } - - /// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_items(mut self, op: TypedOp) -> Self { - self.items.alter_typed(op); - self - } - - // **< Submenu GETTERS >************************************************************************ - - pub fn title(&self) -> &AttrL10n { - &self.title - } - - /// Devuelve la lista de ítems (`children`) del submenú. - pub fn items(&self) -> &Children { - &self.items - } -} diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 20f5199..2f49274 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -51,35 +51,14 @@ impl Theme for Basic { "PageTopIntro" => "/css/intro.css", _ => "/css/basic.css", }; - let pkg_version = env!("CARGO_PKG_VERSION"); page.alter_assets(AssetsOp::AddStyleSheet( StyleSheet::from("/css/normalize.css") .with_version("8.0.1") .with_weight(-99), )) - .alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from("/css/root.css") - .with_version(pkg_version) - .with_weight(-99), - )) - .alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from("/css/components.css") - .with_version(pkg_version) - .with_weight(-99), - )) - .alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from("/css/menu.css") - .with_version(pkg_version) - .with_weight(-99), - )) .alter_assets(AssetsOp::AddStyleSheet( StyleSheet::from(styles) - .with_version(pkg_version) - .with_weight(-99), - )) - .alter_assets(AssetsOp::AddJavaScript( - JavaScript::defer("/js/menu.js") - .with_version(pkg_version) + .with_version(env!("CARGO_PKG_VERSION")) .with_weight(-99), )); } diff --git a/src/html.rs b/src/html.rs index c4195a9..b6815ec 100644 --- a/src/html.rs +++ b/src/html.rs @@ -15,7 +15,6 @@ pub use assets::{Asset, Assets}; mod context; pub use context::{AssetsOp, Context, Contextual, ErrorParam}; -pub type FnPathByContext = fn(cx: &Context) -> &str; // **< HTML ATTRIBUTES >**************************************************************************** diff --git a/static/css/basic.css b/static/css/basic.css index 04801dd..312ddf0 100644 --- a/static/css/basic.css +++ b/static/css/basic.css @@ -3,3 +3,9 @@ .region--footer { padding-bottom: 2rem; } + +/* PoweredBy component */ + +.poweredby { + text-align: center; +} diff --git a/static/css/components.css b/static/css/components.css deleted file mode 100644 index ec5d3f0..0000000 --- a/static/css/components.css +++ /dev/null @@ -1,12 +0,0 @@ -/* Icon component */ - -.icon { - width: 1rem; - height: 1rem; -} - -/* PoweredBy component */ - -.poweredby { - text-align: center; -} diff --git a/static/css/menu.css b/static/css/menu.css deleted file mode 100644 index a8b2854..0000000 --- a/static/css/menu.css +++ /dev/null @@ -1,309 +0,0 @@ -.menu { - width: 100%; - height: auto; - margin: 0; - padding: 0; - z-index: 9999; - border: none; - outline: none; - background: var(--val-menu--color-bg); -} - -.menu__wrapper { - padding-right: var(--val-gap); -} -.menu__wrapper a, -.menu__wrapper button { - cursor: pointer; - border: none; - background: none; - text-decoration: none; -} - -.menu__nav ul { - margin: 0; - padding: 0; -} -.menu__nav li { - display: inline-block; - margin: 0 0 0 1.5rem; - padding: var(--val-menu--line-padding) 0; - line-height: var(--val-menu--line-height); - list-style: none; - list-style-type: none; -} - -.menu__nav li.menu__label, -.menu__nav li > a { - position: relative; - font-weight: 500; - color: var(--val-color--text); - text-rendering: optimizeLegibility; -} -.menu__nav li > a { - border: none; - transition: color 0.3s ease-in-out; -} -.menu__nav li:hover > a, -.menu__nav li > a:focus { - color: var(--val-menu--color-highlight); -} -.menu__nav li > a > i.menu__icon { - margin-left: 0.25rem; -} - -.menu__nav li .menu__subs { - position: absolute; - max-width: 100%; - height: auto; - padding: 1rem 2rem; - border: none; - outline: none; - background: var(--val-menu--color-bg); - border-radius: var(--val-menu--border-radius); - border-top: 3px solid var(--val-menu--color-highlight); - z-index: 500; - opacity: 0; - visibility: hidden; - box-shadow: 0 4px 6px -1px var(--val-menu--color-border), 0 2px 4px -1px var(--val-menu--color-shadow); - transition: all 0.5s ease-in-out; -} - -.menu__nav li.menu__children:hover > .menu__subs, -.menu__nav li.menu__children > a:focus + .menu__subs, -.menu__nav li.menu__children .menu__subs:focus-within { - margin-top: 0.4rem; - opacity: 1; - visibility: visible; -} - -.menu__nav li .menu__items { - min-width: var(--val-menu--item-width-min); - max-width: var(--val-menu--item-width-max); -} -.menu__nav li .menu__items .menu__title { - font-family: inherit; - font-size: 1rem; - font-weight: 500; - margin: 0; - padding: var(--val-menu--line-padding) 0; - line-height: var(--val-menu--line-height); - border: none; - outline: none; - color: var(--val-menu--color-highlight); - text-transform: uppercase; - text-rendering: optimizeLegibility; -} -.menu__nav li .menu__items li { - display: block; - margin-left: 0; -} - -.menu__nav li .menu__mega { - left: 50%; - transform: translateX(-50%); -} - -.menu__nav li .menu__groups { - display: flex; - flex-wrap: nowrap; -} - -.menu__header, -.menu__trigger { - display: none; -} - -/* Applies <= 992px */ -@media only screen and (max-width: 62rem) { - .menu { - border-radius: var(--val-border-radius); - } - .menu__wrapper { - padding-right: var(--val-gap-0-5); - } - .menu__wrapper button { - margin: var(--val-gap-0-5) 0 var(--val-gap-0-5) var(--val-gap-0-5); - } - .menu__trigger { - cursor: pointer; - width: var(--val-menu--trigger-width); - height: var(--val-menu--item-height); - border: none; - outline: none; - background: none; - display: flex; - flex-direction: column; - justify-content: center; - } - .menu__trigger span { - width: 100%; - height: 2px; - margin: 12.675% 0; - border-radius: var(--val-border-radius); - background: var(--val-color--text); - } - - .menu__nav { - position: fixed; - top: 0; - left: 0; - width: var(--val-menu--side-width); - height: 100%; - z-index: 9099; - overflow: hidden; - background: var(--val-menu--color-bg); - transform: translate(-100%); - transition: all 0.5s ease-in-out; - } - .menu__panel .menu__nav.active { - transform: translate(0%); - } - - .menu__nav li { - display: block; - margin: 0; - padding: 0; - } - .menu__nav li.menu__label, - .menu__nav li > a { - display: block; - padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); - border-bottom: 1px solid var(--val-menu--color-border); - } - .menu__nav li ul li.menu__label, - .menu__nav li ul li > a { - border-bottom: 0; - } - .menu__nav li > a > i.menu__icon { - position: absolute; - top: var(--val-menu--line-padding); - right: var(--val-menu--line-padding); - font-size: 1.25rem; - transform: rotate(-90deg); - } - - .menu__nav li .menu__subs { - position: absolute; - display: none; - top: 0; - left: 0; - max-width: none; - min-width: auto; - width: 100%; - height: 100%; - margin: 0 !important; - padding: 0; - border-top: 0; - opacity: 1; - overflow-y: auto; - visibility: visible; - transform: translateX(0%); - box-shadow: none; - } - .menu__nav li .menu__subs.active { - display: block; - } - .menu__nav li .menu__subs > :first-child { - margin-top: 4rem; - } - - .menu__nav li .menu__items .menu__title { - padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); - } - - .menu__nav li .menu__groups { - display: block; - } - - .menu__nav .menu__header { - position: sticky; - display: flex; - align-items: center; - justify-content: space-between; - top: 0; - height: var(--val-menu--item-height); - border-bottom: 1px solid var(--val-menu--color-border); - background: var(--val-menu--color-bg); - z-index: 501; - } - .menu__nav .menu__header .menu__title { - padding: var(--val-menu--line-padding); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - .menu__nav .menu__header .menu__close, - .menu__nav .menu__header .menu__back { - width: var(--val-menu--item-height); - min-width: var(--val-menu--item-height); - height: var(--val-menu--item-height); - line-height: var(--val-menu--item-height); - color: var(--val-color--text); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - } - .menu__nav .menu__header .menu__close { - font-size: 2.25rem; - border-left: 1px solid var(--val-menu--color-border); - } - .menu__nav .menu__header .menu__back { - font-size: 1.25rem; - border-right: 1px solid var(--val-menu--color-border); - display: none; - } - .menu__nav .menu__header.active .menu__back { - display: flex; - } - - .menu__nav .menu__list { - height: 100%; - overflow-y: auto; - overflow-x: hidden; - padding: 0; - margin: 0; - } - - .menu__overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 9098; - opacity: 0; - visibility: hidden; - background: rgba(0, 0, 0, 0.55); - transition: all 0.5s ease-in-out; - } - .menu__overlay.active { - opacity: 1; - visibility: visible; - } -} - -/* ANIMATIONS */ - -@keyframes slideLeft { - 0% { - opacity: 0; - transform: translateX(100%); - } - 100% { - opacity: 1; - transform: translateX(0%); - } -} - -@keyframes slideRight { - 0% { - opacity: 1; - transform: translateX(0%); - } - 100% { - opacity: 0; - transform: translateX(100%); - } -} diff --git a/static/css/root.css b/static/css/root.css deleted file mode 100644 index bc55a44..0000000 --- a/static/css/root.css +++ /dev/null @@ -1,211 +0,0 @@ -:root { - --val-font-sans: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; - --val-font-serif: "Lora","georgia",serif; - --val-font-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; - --val-font-family: var(--val-font-sans); - - /* Font size */ - --val-fs--x3l: 2.5rem; - --val-fs--x2l: 2rem; - --val-fs--xl: 1.75rem; - --val-fs--l: 1.5rem; - --val-fs--m: 1.25rem; - --val-fs--base: 1rem; - --val-fs--s: 0.875rem; - --val-fs--xs: 0.75rem; - --val-fs--x2s: 0.5625rem; - --val-fs--x3s: 0.375rem; - - /* Font weight */ - --val-fw--light: 300; - --val-fw--base: 400; - --val-fw--bold: 500; - - /* Line height */ - --val-lh--base: 1.5; - --val-lh--header: 1.2; - - --val-max-width: 90rem; -/* - --val-color-rgb: 33,37,41; - --val-main--bg-rgb: 255,255,255; - --val-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); - - --line-height-base: 1.6875rem; - --line-height-s: 1.125rem; - --max-bg-color: 98.125rem; -*/ - --val-gap: 1.125rem; -/* - --content-left: 5.625rem; - --site-header-height-wide: var(--val-gap10); - --container-padding: var(--val-gap); -*/ -} -/* -@media (min-width: 75rem) { - :root { - --container-padding:var(--val-gap2); - } -} - -:root { - --scrollbar-width: 0px; - --grid-col-count: 6; - --grid-gap: var(--val-gap); - --grid-gap-count: calc(var(--grid-col-count) - 1); - --grid-full-width: calc(100vw - var(--val-gap2) - var(--scrollbar-width)); - --grid-col-width: calc((var(--grid-full-width) - (var(--grid-gap-count) * var(--grid-gap))) / var(--grid-col-count)); -} - -@media (min-width: 43.75rem) { - :root { - --grid-col-count:14; - --grid-gap: var(--val-gap2); - } -} - -@media (min-width: 62.5rem) { - :root { - --scrollbar-width:0.9375rem; - } -} - -@media (min-width: 75rem) { - :root { - --grid-full-width:calc(100vw - var(--scrollbar-width) - var(--content-left) - var(--val-gap4)); - } -} - -@media (min-width: 90rem) { - :root { - --grid-full-width:calc(var(--max-width) - var(--val-gap4)); - } -} -*/ -:root { - --val-gap-0-15: calc(0.15 * var(--val-gap)); - --val-gap-0-25: calc(0.25 * var(--val-gap)); - --val-gap-0-35: calc(0.35 * var(--val-gap)); - --val-gap-0-5: calc(0.5 * var(--val-gap)); - --val-gap-0-75: calc(0.75 * var(--val-gap)); - --val-gap-1-5: calc(1.5 * var(--val-gap)); - --val-gap-2: calc(2 * var(--val-gap)); - - --primary-hue: 216; - --primary-sat: 60%; - --val-color--primary: hsl(var(--primary-hue), var(--primary-sat), 50%); - --val-color--primary-light: hsl(var(--primary-hue), var(--primary-sat), 60%); - --val-color--primary-dark: hsl(var(--primary-hue), var(--primary-sat), 40%); - --val-color--primary-link: hsl(var(--primary-hue), var(--primary-sat), 55%); - --val-color--primary-link-hover: hsl(var(--primary-hue), var(--primary-sat), 30%); - --val-color--primary-link-active: hsl(var(--primary-hue), var(--primary-sat), 70%); - - --info-hue: 190; - --info-sat: 90%; - --val-color--info: hsl(var(--info-hue), var(--info-sat), 54%); - --val-color--info-light: hsl(var(--info-hue), var(--info-sat), 70%); - --val-color--info-dark: hsl(var(--info-hue), var(--info-sat), 45%); - --val-color--info-link: hsl(var(--info-hue), var(--info-sat), 30%); - --val-color--info-link-hover: hsl(var(--info-hue), var(--info-sat), 20%); - --val-color--info-link-active: hsl(var(--info-hue), var(--info-sat), 40%); - - --success-hue: 150; - --success-sat: 50%; - --val-color--success: hsl(var(--success-hue), var(--success-sat), 50%); - --val-color--success-light: hsl(var(--success-hue), var(--success-sat), 68%); - --val-color--success-dark: hsl(var(--success-hue), var(--success-sat), 38%); - --val-color--success-link: hsl(var(--success-hue), var(--success-sat), 26%); - --val-color--success-link-hover: hsl(var(--success-hue), var(--success-sat), 18%); - --val-color--success-link-active: hsl(var(--success-hue), var(--success-sat), 36%); - - --warning-hue: 44; - --warning-sat: 100%; - --val-color--warning: hsl(var(--warning-hue), var(--warning-sat), 50%); - --val-color--warning-light: hsl(var(--warning-hue), var(--warning-sat), 60%); - --val-color--warning-dark: hsl(var(--warning-hue), var(--warning-sat), 40%); - --val-color--warning-link: hsl(var(--warning-hue), var(--warning-sat), 30%); - --val-color--warning-link-hover: hsl(var(--warning-hue), var(--warning-sat), 20%); - --val-color--warning-link-active: hsl(var(--warning-hue), var(--warning-sat), 38%); - - --danger-hue: 348; - --danger-sat: 86%; - --val-color--danger: hsl(var(--danger-hue), var(--danger-sat), 50%); - --val-color--danger-light: hsl(var(--danger-hue), var(--danger-sat), 60%); - --val-color--danger-dark: hsl(var(--danger-hue), var(--danger-sat), 35%); - --val-color--danger-link: hsl(var(--danger-hue), var(--danger-sat), 25%); - --val-color--danger-link-hover: hsl(var(--danger-hue), var(--danger-sat), 10%); - --val-color--danger-link-active: hsl(var(--danger-hue), var(--danger-sat), 30%); - - --light-hue: 0; - --light-sat: 0%; - --val-color--light: hsl(var(--light-hue), var(--light-sat), 96%); - --val-color--light-light: hsl(var(--light-hue), var(--light-sat), 98%); - --val-color--light-dark: hsl(var(--light-hue), var(--light-sat), 92%); - - --dark-hue: 0; - --dark-sat: 0%; - --val-color--dark: hsl(var(--dark-hue), var(--dark-sat), 25%); - --val-color--dark-light: hsl(var(--dark-hue), var(--dark-sat), 40%); - --val-color--dark-dark: hsl(var(--dark-hue), var(--dark-sat), 8%); - --val-color--dark-link: hsl(var(--dark-hue), var(--dark-sat), 90%); - --val-color--dark-link-hover: hsl(var(--dark-hue), var(--dark-sat), 100%); - --val-color--dark-link-active: hsl(var(--dark-hue), var(--dark-sat), 70%); - - - - - --gray-hue: 201; - --gray-sat: 15%; - --val-color--gray-5: hsl(var(--gray-hue), var(--gray-sat), 5%); - --val-color--gray-10: hsl(var(--gray-hue), var(--gray-sat) ,11%); - --val-color--gray-20: hsl(var(--gray-hue), var(--gray-sat),20%); - --val-color--gray-45: hsl(var(--gray-hue), var(--gray-sat), 44%); - --val-color--gray-60: hsl(var(--gray-hue), var(--gray-sat), 57%); - --val-color--gray-65: hsl(var(--gray-hue), var(--gray-sat), 63%); - --val-color--gray-70: hsl(var(--gray-hue), var(--gray-sat), 72%); - --val-color--gray-90: hsl(var(--gray-hue), var(--gray-sat), 88%); - --val-color--gray-95: hsl(var(--gray-hue), var(--gray-sat), 93%); - --val-color--gray-100: hsl(var(--gray-hue), var(--gray-sat), 97%); - - - - - --val-color--bg: #fafafa; - --val-color--text: #212529; - --val-color--white: #fff; - -/* - - - --color-text-neutral-soft: var(--color--gray-45); - --color-text-neutral-medium: var(--color--gray-20); - --color-text-neutral-loud: var(--color--gray-5); - --color-text-primary-medium: var(--val-color--primary-40); - --color-text-primary-loud: var(--val-color--primary-30); - --color--black: #000; -*/ -/* - --color--red: #e33f1e; - --color--gold: #fdca40; - --color--green: #3fa21c; - --header-height-wide-when-fixed: calc(6 * var(--val-gap)); - --mobile-nav-width: 31.25rem; -*/ - --val-border-radius: 0.375rem; - - /* Menu component */ - --val-menu--color-bg: var(--val-color--bg); - --val-menu--color-highlight: #e91e63; - --val-menu--color-border: rgba(0, 0, 0, 0.1); - --val-menu--color-shadow: rgba(0, 0, 0, 0.06); - --val-menu--line-padding: 0.625rem; - --val-menu--line-height: calc(1.875rem + 1px); - --val-menu--item-height: calc(var(--val-menu--line-padding) + var(--val-menu--line-height)); - --val-menu--item-width-min: 14rem; - --val-menu--item-width-max: 20rem; - --val-menu--item-gap: 1rem; - --val-menu--border-radius: 0.625rem; - --val-menu--trigger-width: var(--val-menu--item-height); - --val-menu--side-width: 20rem; -} diff --git a/static/js/menu.js b/static/js/menu.js deleted file mode 100644 index 2f3b332..0000000 --- a/static/js/menu.js +++ /dev/null @@ -1,94 +0,0 @@ -function menu__showChildren(nav, children) { - let submenu = children[0].querySelector('.menu__subs'); - submenu.classList.add('active'); - submenu.style.animation = 'slideLeft 0.5s ease forwards'; - - let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; - nav.querySelector('.menu__title').innerHTML = title; - nav.querySelector('.menu__header').classList.add('active'); -} - -function menu__hideChildren(nav, children) { - let submenu = children[0].querySelector('.menu__subs'); - submenu.style.animation = 'slideRight 0.5s ease forwards'; - setTimeout(() => { - submenu.classList.remove('active'); - submenu.style.removeProperty('animation'); - }, 300); - - children.shift(); - if (children.length > 0) { - let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; - nav.querySelector('.menu__title').innerHTML = title; - } else { - nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').innerHTML = ''; - } -} - -function menu__toggle(nav, overlay) { - nav.classList.toggle('active'); - overlay.classList.toggle('active'); -} - -function menu__reset(menu, nav, overlay) { - menu__toggle(nav, overlay); - setTimeout(() => { - nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').innerHTML = ''; - menu.querySelectorAll('.menu__subs').forEach(submenu => { - submenu.classList.remove('active'); - submenu.style.removeProperty('animation'); - }); - }, 300); - return []; -} - -document.querySelectorAll('.menu').forEach(menu => { - - let menuChildren = []; - const menuNav = menu.querySelector('.menu__nav'); - const menuOverlay = menu.querySelector('.menu__overlay'); - - menu.querySelector('.menu__list').addEventListener('click', (e) => { - if (menuNav.classList.contains('active')) { - let target = e.target.closest('.menu__children'); - if (target && target != menuChildren[0]) { - menuChildren.unshift(target); - menu__showChildren(menuNav, menuChildren); - } - } - }); - - menu.querySelector('.menu__back').addEventListener('click', () => { - menu__hideChildren(menuNav, menuChildren); - }); - - menu.querySelector('.menu__close').addEventListener('click', () => { - menuChildren = menu__reset(menu, menuNav, menuOverlay); - }); - - menu.querySelectorAll('.menu__link > a[target="_blank"]').forEach(link => { - link.addEventListener('click', (e) => { - menuChildren = menu__reset(menu, menuNav, menuOverlay); - e.target.blur(); - }); - }); - - menu.querySelector('.menu__trigger').addEventListener('click', () => { - menu__toggle(menuNav, menuOverlay); - }); - - menuOverlay.addEventListener('click', () => { - menu__toggle(menuNav, menuOverlay); - }); - - window.onresize = function () { - if (menuNav.classList.contains('active')) { - var fontSizeRoot = parseFloat(getComputedStyle(document.documentElement).fontSize); - if (this.innerWidth >= 62 * fontSizeRoot) { - menuChildren = menu__reset(menu, menuNav, menuOverlay); - } - } - }; -});