🚚 Gran actualización de Paquetes a Extensiones
This commit is contained in:
parent
f6b76caf8d
commit
3faaaa76ee
443 changed files with 1123 additions and 444 deletions
172
extensions/pagetop-bootsier/src/bs/container.rs
Normal file
172
extensions/pagetop-bootsier/src/bs/container.rs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::BreakPoint;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ContainerType {
|
||||
#[default]
|
||||
Default, // Contenedor genérico
|
||||
Main, // Contenido principal
|
||||
Header, // Encabezado
|
||||
Footer, // Pie
|
||||
Section, // Sección específica de contenido
|
||||
Article, // Artículo dentro de una sección
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Container {
|
||||
id : OptionId,
|
||||
classes : OptionClasses,
|
||||
container_type: ContainerType,
|
||||
breakpoint : BreakPoint,
|
||||
children : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Container {
|
||||
fn new() -> Self {
|
||||
Container::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(
|
||||
ClassesOp::Prepend,
|
||||
trio_string!("container", "-", self.breakpoint().to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let output = self.children().render(cx);
|
||||
if output.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
let style = if let BreakPoint::FluidMax(max_width) = self.breakpoint() {
|
||||
Some(join_string!("max-width: ", max_width.to_string(), ";"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match self.container_type() {
|
||||
ContainerType::Default => PrepareMarkup::With(html! {
|
||||
div id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
}),
|
||||
ContainerType::Main => PrepareMarkup::With(html! {
|
||||
main id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
}),
|
||||
ContainerType::Header => PrepareMarkup::With(html! {
|
||||
header id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
}),
|
||||
ContainerType::Footer => PrepareMarkup::With(html! {
|
||||
footer id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
}),
|
||||
ContainerType::Section => PrepareMarkup::With(html! {
|
||||
section id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
}),
|
||||
ContainerType::Article => PrepareMarkup::With(html! {
|
||||
article id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
pub fn main() -> Self {
|
||||
Container {
|
||||
container_type: ContainerType::Main,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header() -> Self {
|
||||
Container {
|
||||
container_type: ContainerType::Header,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn footer() -> Self {
|
||||
Container {
|
||||
container_type: ContainerType::Footer,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn section() -> Self {
|
||||
Container {
|
||||
container_type: ContainerType::Section,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn article() -> Self {
|
||||
Container {
|
||||
container_type: ContainerType::Article,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
// Container BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self {
|
||||
self.breakpoint = bp;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_child(mut self, child: impl ComponentTrait) -> Self {
|
||||
self.children.add(Child::with(child));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_children(mut self, op: ChildOp) -> Self {
|
||||
self.children.alter_child(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Container GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn container_type(&self) -> &ContainerType {
|
||||
&self.container_type
|
||||
}
|
||||
|
||||
pub fn breakpoint(&self) -> &BreakPoint {
|
||||
&self.breakpoint
|
||||
}
|
||||
|
||||
pub fn children(&self) -> &Children {
|
||||
&self.children
|
||||
}
|
||||
}
|
||||
5
extensions/pagetop-bootsier/src/bs/dropdown.rs
Normal file
5
extensions/pagetop-bootsier/src/bs/dropdown.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod component;
|
||||
pub use component::Dropdown;
|
||||
|
||||
mod item;
|
||||
pub use item::Item;
|
||||
99
extensions/pagetop-bootsier/src/bs/dropdown/component.rs
Normal file
99
extensions/pagetop-bootsier/src/bs/dropdown/component.rs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::dropdown;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Dropdown {
|
||||
id : OptionId,
|
||||
classes: OptionClasses,
|
||||
items : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Dropdown {
|
||||
fn new() -> Self {
|
||||
Dropdown::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(ClassesOp::Prepend, "dropdown");
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let items = self.items().render(cx);
|
||||
if items.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
div id=[self.id()] class=[self.classes().get()] {
|
||||
button
|
||||
type="button"
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
{
|
||||
("Dropdown button")
|
||||
}
|
||||
ul class="dropdown-menu" {
|
||||
li {
|
||||
a class="dropdown-item" href="#" {
|
||||
("Action")
|
||||
}
|
||||
}
|
||||
li {
|
||||
a class="dropdown-item" href="#" {
|
||||
("Another action")
|
||||
}
|
||||
}
|
||||
li {
|
||||
a class="dropdown-item" href="#" {
|
||||
("Something else here")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Dropdown {
|
||||
// Dropdown BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_item(mut self, item: dropdown::Item) -> Self {
|
||||
self.items.add(Child::with(item));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_items(mut self, op: TypedOp<dropdown::Item>) -> Self {
|
||||
self.items.alter_typed(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Dropdown GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn items(&self) -> &Children {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
109
extensions/pagetop-bootsier/src/bs/dropdown/item.rs
Normal file
109
extensions/pagetop-bootsier/src/bs/dropdown/item.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
type Label = L10n;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ItemType {
|
||||
#[default]
|
||||
Void,
|
||||
Label(Label),
|
||||
Link(Label, FnContextualPath),
|
||||
LinkBlank(Label, FnContextualPath),
|
||||
}
|
||||
|
||||
// Item.
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Item {
|
||||
item_type: ItemType,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Item {
|
||||
fn new() -> Self {
|
||||
Item::default()
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let description: Option<String> = None;
|
||||
|
||||
// Obtiene la URL actual desde `cx.request`.
|
||||
let current_path = cx.request().path();
|
||||
|
||||
match self.item_type() {
|
||||
ItemType::Void => PrepareMarkup::None,
|
||||
ItemType::Label(label) => PrepareMarkup::With(html! {
|
||||
li class="dropdown-item" {
|
||||
span title=[description] {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
}),
|
||||
ItemType::Link(label, path) => {
|
||||
let item_path = path(cx);
|
||||
let (class, aria) = if item_path == current_path {
|
||||
("dropdown-item active", Some("page"))
|
||||
} else {
|
||||
("dropdown-item", None)
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
li class=(class) aria-current=[aria] {
|
||||
a class="nav-link" href=(item_path) title=[description] {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
ItemType::LinkBlank(label, path) => {
|
||||
let item_path = path(cx);
|
||||
let (class, aria) = if item_path == current_path {
|
||||
("dropdown-item active", Some("page"))
|
||||
} else {
|
||||
("dropdown-item", None)
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
li class=(class) aria-current=[aria] {
|
||||
a class="nav-link" href=(item_path) title=[description] target="_blank" {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn label(label: L10n) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::Label(label),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link(label: L10n, path: FnContextualPath) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::Link(label, path),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link_blank(label: L10n, path: FnContextualPath) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::LinkBlank(label, path),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
// Item GETTERS.
|
||||
|
||||
pub fn item_type(&self) -> &ItemType {
|
||||
&self.item_type
|
||||
}
|
||||
}
|
||||
110
extensions/pagetop-bootsier/src/bs/grid.rs
Normal file
110
extensions/pagetop-bootsier/src/bs/grid.rs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::BreakPoint;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
mod component;
|
||||
pub use component::Grid;
|
||||
|
||||
mod item;
|
||||
pub use item::Item;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Layout {
|
||||
#[default]
|
||||
Default,
|
||||
Rows(u8),
|
||||
Cols(u8),
|
||||
Grid(u8, u8),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for Layout {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Layout::Rows(r) if *r > 1 => write!(f, "--bs-rows: {r};"),
|
||||
Layout::Cols(c) if *c > 0 => write!(f, "--bs-columns: {c};"),
|
||||
Layout::Grid(r, c) => write!(f, "{}", trio_string!(
|
||||
Layout::Rows(*r).to_string(), " ", Layout::Cols(*c).to_string()
|
||||
)),
|
||||
_ => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Gap {
|
||||
#[default]
|
||||
Default,
|
||||
Row(unit::Value),
|
||||
Col(unit::Value),
|
||||
Grid(unit::Value, unit::Value),
|
||||
Both(unit::Value),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for Gap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Gap::Default => write!(f, ""),
|
||||
Gap::Row(r) => write!(f, "row-gap: {r};"),
|
||||
Gap::Col(c) => write!(f, "column-gap: {c};"),
|
||||
Gap::Grid(r, c) => write!(f, "--bs-gap: {r} {c};"),
|
||||
Gap::Both(v) => write!(f, "--bs-gap: {v};"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ItemColumns {
|
||||
#[default]
|
||||
Default,
|
||||
Cols(u8),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ItemColumns {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ItemColumns::Cols(c) if *c > 1 => write!(f, "g-col-{c}"),
|
||||
_ => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ItemResponsive {
|
||||
#[default]
|
||||
Default,
|
||||
Cols(BreakPoint, u8),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ItemResponsive {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ItemResponsive::Cols(bp, c) if bp.is_breakpoint() && *c > 0 => {
|
||||
write!(f, "g-col-{bp}-{c}")
|
||||
}
|
||||
_ => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ItemStart {
|
||||
#[default]
|
||||
Default,
|
||||
Col(u8),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ItemStart {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ItemStart::Col(c) if *c > 1 => write!(f, "g-start-{c}"),
|
||||
_ => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
103
extensions/pagetop-bootsier/src/bs/grid/component.rs
Normal file
103
extensions/pagetop-bootsier/src/bs/grid/component.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::grid;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Grid {
|
||||
id : OptionId,
|
||||
classes : OptionClasses,
|
||||
grid_layout: grid::Layout,
|
||||
grid_gap : grid::Gap,
|
||||
items : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Grid {
|
||||
fn new() -> Self {
|
||||
Grid::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(ClassesOp::Prepend, "grid");
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let output = self.items().render(cx);
|
||||
if output.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
|
||||
let style = option_string!([self.layout().to_string(), self.gap().to_string()]; " ");
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
div id=[self.id()] class=[self.classes().get()] style=[style] {
|
||||
(output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
pub fn with(item: grid::Item) -> Self {
|
||||
Grid::default().with_item(item)
|
||||
}
|
||||
|
||||
// Grid BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_layout(mut self, layout: grid::Layout) -> Self {
|
||||
self.grid_layout = layout;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_gap(mut self, gap: grid::Gap) -> Self {
|
||||
self.grid_gap = gap;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_item(mut self, item: grid::Item) -> Self {
|
||||
self.items.add(Child::with(item));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_items(mut self, op: TypedOp<grid::Item>) -> Self {
|
||||
self.items.alter_typed(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Grid GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn layout(&self) -> &grid::Layout {
|
||||
&self.grid_layout
|
||||
}
|
||||
|
||||
pub fn gap(&self) -> &grid::Gap {
|
||||
&self.grid_gap
|
||||
}
|
||||
|
||||
pub fn items(&self) -> &Children {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
119
extensions/pagetop-bootsier/src/bs/grid/item.rs
Normal file
119
extensions/pagetop-bootsier/src/bs/grid/item.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::grid;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Item {
|
||||
id : OptionId,
|
||||
classes : OptionClasses,
|
||||
columns : grid::ItemColumns,
|
||||
responsive: grid::ItemResponsive,
|
||||
start : grid::ItemStart,
|
||||
children : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Item {
|
||||
fn new() -> Self {
|
||||
Item::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(
|
||||
ClassesOp::Prepend,
|
||||
[
|
||||
self.columns().to_string(),
|
||||
self.responsive().to_string(),
|
||||
self.start().to_string(),
|
||||
]
|
||||
.join(" "),
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let output = self.children().render(cx);
|
||||
if output.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
PrepareMarkup::With(html! {
|
||||
div id=[self.id()] class=[self.classes().get()] {
|
||||
(output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn with(child: impl ComponentTrait) -> Self {
|
||||
Item::default().with_child(child)
|
||||
}
|
||||
|
||||
// Item BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_columns(mut self, columns: grid::ItemColumns) -> Self {
|
||||
self.columns = columns;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_responsive(mut self, responsive: grid::ItemResponsive) -> Self {
|
||||
self.responsive = responsive;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_start(mut self, start: grid::ItemStart) -> Self {
|
||||
self.start = start;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_child(mut self, child: impl ComponentTrait) -> Self {
|
||||
self.children.add(Child::with(child));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_children(mut self, op: ChildOp) -> Self {
|
||||
self.children.alter_child(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Item GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn columns(&self) -> &grid::ItemColumns {
|
||||
&self.columns
|
||||
}
|
||||
|
||||
pub fn responsive(&self) -> &grid::ItemResponsive {
|
||||
&self.responsive
|
||||
}
|
||||
|
||||
pub fn start(&self) -> &grid::ItemStart {
|
||||
&self.start
|
||||
}
|
||||
|
||||
pub fn children(&self) -> &Children {
|
||||
&self.children
|
||||
}
|
||||
}
|
||||
157
extensions/pagetop-bootsier/src/bs/image.rs
Normal file
157
extensions/pagetop-bootsier/src/bs/image.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::Border;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ImageType {
|
||||
#[default]
|
||||
Fluid,
|
||||
Thumbnail,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ImageType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ImageType::Fluid => write!(f, "img-fluid"),
|
||||
ImageType::Thumbnail => write!(f, "img-thumbnail"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ImageSize {
|
||||
#[default]
|
||||
Auto,
|
||||
Size(u16, u16),
|
||||
Width(u16),
|
||||
Height(u16),
|
||||
Both(u16),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Image {
|
||||
id : OptionId,
|
||||
classes : OptionClasses,
|
||||
image_type: ImageType,
|
||||
source : OptionString,
|
||||
size : ImageSize,
|
||||
border : Border,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Image {
|
||||
fn new() -> Self {
|
||||
Image::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(
|
||||
ClassesOp::Prepend,
|
||||
[self.image_type().to_string()].join(" "),
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup {
|
||||
let (width, height) = match self.size() {
|
||||
ImageSize::Auto => (None, None),
|
||||
ImageSize::Size(width, height) => (Some(width), Some(height)),
|
||||
ImageSize::Width(width) => (Some(width), None),
|
||||
ImageSize::Height(height) => (None, Some(height)),
|
||||
ImageSize::Both(value) => (Some(value), Some(value)),
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
img
|
||||
src=[self.source().get()]
|
||||
id=[self.id()]
|
||||
class=[self.classes().get()]
|
||||
width=[width]
|
||||
height=[height] {}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub fn with(source: &str) -> Self {
|
||||
Image::default().with_source(source)
|
||||
}
|
||||
|
||||
pub fn thumbnail(source: &str) -> Self {
|
||||
Image::default()
|
||||
.with_source(source)
|
||||
.with_image_type(ImageType::Thumbnail)
|
||||
}
|
||||
/*
|
||||
pub fn pagetop() -> Self {
|
||||
Image::default()
|
||||
.with_source("/base/pagetop-logo.svg")
|
||||
.with_classes(ClassesOp::Add, IMG_FIXED)
|
||||
.with_size(ImageSize::Size(64, 64))
|
||||
}
|
||||
*/
|
||||
// Image BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_image_type(mut self, image_type: ImageType) -> Self {
|
||||
self.image_type = image_type;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_source(mut self, source: &str) -> Self {
|
||||
self.source.alter_value(source);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_size(mut self, size: ImageSize) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_border(mut self, border: Border) -> Self {
|
||||
self.border = border;
|
||||
self
|
||||
}
|
||||
|
||||
// Image GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn image_type(&self) -> &ImageType {
|
||||
&self.image_type
|
||||
}
|
||||
|
||||
pub fn source(&self) -> &OptionString {
|
||||
&self.source
|
||||
}
|
||||
|
||||
pub fn size(&self) -> &ImageSize {
|
||||
&self.size
|
||||
}
|
||||
|
||||
pub fn border(&self) -> &Border {
|
||||
&self.border
|
||||
}
|
||||
}
|
||||
11
extensions/pagetop-bootsier/src/bs/navbar.rs
Normal file
11
extensions/pagetop-bootsier/src/bs/navbar.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
mod component;
|
||||
pub use component::{Navbar, NavbarContent, NavbarToggler};
|
||||
|
||||
//mod brand;
|
||||
//pub use brand::Brand;
|
||||
|
||||
mod nav;
|
||||
pub use nav::Nav;
|
||||
|
||||
mod item;
|
||||
pub use item::{Item, ItemType};
|
||||
102
extensions/pagetop-bootsier/src/bs/navbar/brand.rs
Normal file
102
extensions/pagetop-bootsier/src/bs/navbar/brand.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Brand {
|
||||
id : OptionId,
|
||||
#[default(_code = "global::SETTINGS.app.name.to_owned()")]
|
||||
app_name : String,
|
||||
slogan : OptionTranslated,
|
||||
logo : OptionComponent<Image>,
|
||||
#[default(_code = "|_| \"/\"")]
|
||||
home : FnContextualPath,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Brand {
|
||||
fn new() -> Self {
|
||||
Brand::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let logo = self.logo().render(cx);
|
||||
let home = self.home()(cx);
|
||||
let title = &L10n::l("site_home").using(cx.langid());
|
||||
PrepareMarkup::With(html! {
|
||||
div id=[self.id()] class="branding__container" {
|
||||
div class="branding__content" {
|
||||
@if !logo.is_empty() {
|
||||
a class="branding__logo" href=(home) title=[title] rel="home" {
|
||||
(logo)
|
||||
}
|
||||
}
|
||||
div class="branding__text" {
|
||||
a class="branding__name" href=(home) title=[title] rel="home" {
|
||||
(self.app_name())
|
||||
}
|
||||
@if let Some(slogan) = self.slogan().using(cx.langid()) {
|
||||
div class="branding__slogan" {
|
||||
(slogan)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Brand {
|
||||
// Brand BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_app_name(mut self, app_name: impl Into<String>) -> Self {
|
||||
self.app_name = app_name.into();
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_slogan(mut self, slogan: L10n) -> Self {
|
||||
self.slogan.alter_value(slogan);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_logo(mut self, logo: Option<Image>) -> Self {
|
||||
self.logo.alter_value(logo);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_home(mut self, home: FnContextualPath) -> Self {
|
||||
self.home = home;
|
||||
self
|
||||
}
|
||||
|
||||
// Brand GETTERS.
|
||||
|
||||
pub fn app_name(&self) -> &String {
|
||||
&self.app_name
|
||||
}
|
||||
|
||||
pub fn slogan(&self) -> &OptionTranslated {
|
||||
&self.slogan
|
||||
}
|
||||
|
||||
pub fn logo(&self) -> &OptionComponent<Image> {
|
||||
&self.logo
|
||||
}
|
||||
|
||||
pub fn home(&self) -> &FnContextualPath {
|
||||
&self.home
|
||||
}
|
||||
}
|
||||
202
extensions/pagetop-bootsier/src/bs/navbar/component.rs
Normal file
202
extensions/pagetop-bootsier/src/bs/navbar/component.rs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::navbar;
|
||||
use crate::bs::{BreakPoint, Offcanvas};
|
||||
use crate::LOCALES_BOOTSIER;
|
||||
|
||||
const TOGGLE_COLLAPSE: &str = "collapse";
|
||||
const TOGGLE_OFFCANVAS: &str = "offcanvas";
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum NavbarToggler {
|
||||
#[default]
|
||||
Enabled,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum NavbarContent {
|
||||
#[default]
|
||||
None,
|
||||
Nav(Typed<navbar::Nav>),
|
||||
Offcanvas(Typed<Offcanvas>),
|
||||
Text(L10n),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Navbar {
|
||||
id : OptionId,
|
||||
classes: OptionClasses,
|
||||
expand : BreakPoint,
|
||||
toggler: NavbarToggler,
|
||||
content: NavbarContent,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Navbar {
|
||||
fn new() -> Self {
|
||||
Navbar::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(
|
||||
ClassesOp::Prepend,
|
||||
[
|
||||
"navbar".to_string(),
|
||||
self.expand().try_class("navbar-expand").unwrap_or_default(),
|
||||
]
|
||||
.join(" "),
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let id = cx.required_id::<Self>(self.id());
|
||||
|
||||
let content = match self.content() {
|
||||
NavbarContent::None => return PrepareMarkup::None,
|
||||
NavbarContent::Nav(nav) => {
|
||||
let id_content = join_string!(id, "-content");
|
||||
match self.toggler() {
|
||||
NavbarToggler::Enabled => self.toggler_wrapper(
|
||||
TOGGLE_COLLAPSE,
|
||||
L10n::t("toggle", &LOCALES_BOOTSIER).using(cx.langid()),
|
||||
id_content,
|
||||
nav.render(cx),
|
||||
),
|
||||
NavbarToggler::Disabled => nav.render(cx),
|
||||
}
|
||||
}
|
||||
NavbarContent::Offcanvas(oc) => {
|
||||
let id_content = oc.id().unwrap_or_default();
|
||||
self.toggler_wrapper(
|
||||
TOGGLE_OFFCANVAS,
|
||||
L10n::t("toggle", &LOCALES_BOOTSIER).using(cx.langid()),
|
||||
id_content,
|
||||
oc.render(cx),
|
||||
)
|
||||
}
|
||||
NavbarContent::Text(text) => html! {
|
||||
span class="navbar-text" {
|
||||
(text.escaped(cx.langid()))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
self.nav_wrapper(id, content)
|
||||
}
|
||||
}
|
||||
|
||||
impl Navbar {
|
||||
pub fn with_nav(nav: navbar::Nav) -> Self {
|
||||
Navbar::default().with_content(NavbarContent::Nav(Typed::with(nav)))
|
||||
}
|
||||
|
||||
pub fn with_offcanvas(offcanvas: Offcanvas) -> Self {
|
||||
Navbar::default().with_content(NavbarContent::Offcanvas(Typed::with(offcanvas)))
|
||||
}
|
||||
|
||||
// Navbar BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_expand(mut self, bp: BreakPoint) -> Self {
|
||||
self.expand = bp;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_toggler(mut self, toggler: NavbarToggler) -> Self {
|
||||
self.toggler = toggler;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_content(mut self, content: NavbarContent) -> Self {
|
||||
self.content = content;
|
||||
self
|
||||
}
|
||||
|
||||
// Navbar GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn expand(&self) -> &BreakPoint {
|
||||
&self.expand
|
||||
}
|
||||
|
||||
pub fn toggler(&self) -> &NavbarToggler {
|
||||
&self.toggler
|
||||
}
|
||||
|
||||
pub fn content(&self) -> &NavbarContent {
|
||||
&self.content
|
||||
}
|
||||
|
||||
// Navbar HELPERS.
|
||||
|
||||
fn nav_wrapper(&self, id: String, content: Markup) -> PrepareMarkup {
|
||||
if content.is_empty() {
|
||||
PrepareMarkup::None
|
||||
} else {
|
||||
PrepareMarkup::With(html! {
|
||||
nav id=(id) class=[self.classes().get()] {
|
||||
div class="container-fluid" {
|
||||
(content)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn toggler_wrapper(
|
||||
&self,
|
||||
data_bs_toggle: &str,
|
||||
aria_label: Option<String>,
|
||||
id_content: String,
|
||||
content: Markup,
|
||||
) -> Markup {
|
||||
if content.is_empty() {
|
||||
html! {}
|
||||
} else {
|
||||
let id_content_target = join_string!("#", id_content);
|
||||
let aria_expanded = if data_bs_toggle == TOGGLE_COLLAPSE {
|
||||
Some("false")
|
||||
} else {
|
||||
None
|
||||
};
|
||||
html! {
|
||||
button
|
||||
type="button"
|
||||
class="navbar-toggler"
|
||||
data-bs-toggle=(data_bs_toggle)
|
||||
data-bs-target=(id_content_target)
|
||||
aria-controls=(id_content)
|
||||
aria-expanded=[aria_expanded]
|
||||
aria-label=[aria_label]
|
||||
{
|
||||
span class="navbar-toggler-icon" {}
|
||||
}
|
||||
div id=(id_content) class="collapse navbar-collapse" {
|
||||
(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
extensions/pagetop-bootsier/src/bs/navbar/item.rs
Normal file
113
extensions/pagetop-bootsier/src/bs/navbar/item.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::Dropdown;
|
||||
|
||||
type Label = L10n;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ItemType {
|
||||
#[default]
|
||||
Void,
|
||||
Label(Label),
|
||||
Link(Label, FnContextualPath),
|
||||
LinkBlank(Label, FnContextualPath),
|
||||
Dropdown(Typed<Dropdown>),
|
||||
}
|
||||
|
||||
// Item.
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Item {
|
||||
item_type: ItemType,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Item {
|
||||
fn new() -> Self {
|
||||
Item::default()
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let description: Option<String> = None;
|
||||
|
||||
// Obtiene la URL actual desde `cx.request`.
|
||||
let current_path = cx.request().path();
|
||||
|
||||
match self.item_type() {
|
||||
ItemType::Void => PrepareMarkup::None,
|
||||
ItemType::Label(label) => PrepareMarkup::With(html! {
|
||||
li class="nav-item" {
|
||||
span title=[description] {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
}),
|
||||
ItemType::Link(label, path) => {
|
||||
let item_path = path(cx);
|
||||
let (class, aria) = if item_path == current_path {
|
||||
("nav-item active", Some("page"))
|
||||
} else {
|
||||
("nav-item", None)
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
li class=(class) aria-current=[aria] {
|
||||
a class="nav-link" href=(item_path) title=[description] {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
ItemType::LinkBlank(label, path) => {
|
||||
let item_path = path(cx);
|
||||
let (class, aria) = if item_path == current_path {
|
||||
("nav-item active", Some("page"))
|
||||
} else {
|
||||
("nav-item", None)
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
li class=(class) aria-current=[aria] {
|
||||
a class="nav-link" href=(item_path) title=[description] target="_blank" {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
ItemType::Dropdown(menu) => PrepareMarkup::With(html! { (menu.render(cx)) }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn label(label: L10n) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::Label(label),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link(label: L10n, path: FnContextualPath) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::Link(label, path),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link_blank(label: L10n, path: FnContextualPath) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::LinkBlank(label, path),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
// Item GETTERS.
|
||||
|
||||
pub fn item_type(&self) -> &ItemType {
|
||||
&self.item_type
|
||||
}
|
||||
}
|
||||
75
extensions/pagetop-bootsier/src/bs/navbar/nav.rs
Normal file
75
extensions/pagetop-bootsier/src/bs/navbar/nav.rs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::navbar;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Nav {
|
||||
id : OptionId,
|
||||
classes: OptionClasses,
|
||||
items : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Nav {
|
||||
fn new() -> Self {
|
||||
Nav::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(ClassesOp::Prepend, "navbar-nav");
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let items = self.items().render(cx);
|
||||
if items.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
ul id=[self.id()] class=[self.classes().get()] {
|
||||
(items)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Nav {
|
||||
// Nav BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_item(mut self, item: navbar::Item) -> Self {
|
||||
self.items.add(Child::with(item));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_items(mut self, op: TypedOp<navbar::Item>) -> Self {
|
||||
self.items.alter_typed(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Nav GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn items(&self) -> &Children {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
59
extensions/pagetop-bootsier/src/bs/offcanvas.rs
Normal file
59
extensions/pagetop-bootsier/src/bs/offcanvas.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
mod component;
|
||||
pub use component::Offcanvas;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum OffcanvasPlacement {
|
||||
#[default]
|
||||
Start,
|
||||
End,
|
||||
Top,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for OffcanvasPlacement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
OffcanvasPlacement::Start => write!(f, "offcanvas-start"),
|
||||
OffcanvasPlacement::End => write!(f, "offcanvas-end"),
|
||||
OffcanvasPlacement::Top => write!(f, "offcanvas-top"),
|
||||
OffcanvasPlacement::Bottom => write!(f, "offcanvas-bottom"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum OffcanvasVisibility {
|
||||
#[default]
|
||||
Default,
|
||||
Show,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for OffcanvasVisibility {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
OffcanvasVisibility::Default => write!(f, "show"),
|
||||
OffcanvasVisibility::Show => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum OffcanvasBodyScroll {
|
||||
#[default]
|
||||
Disabled,
|
||||
Enabled,
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum OffcanvasBackdrop {
|
||||
Disabled,
|
||||
#[default]
|
||||
Enabled,
|
||||
Static,
|
||||
}
|
||||
187
extensions/pagetop-bootsier/src/bs/offcanvas/component.rs
Normal file
187
extensions/pagetop-bootsier/src/bs/offcanvas/component.rs
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::BreakPoint;
|
||||
use crate::bs::{OffcanvasBackdrop, OffcanvasBodyScroll, OffcanvasPlacement, OffcanvasVisibility};
|
||||
use crate::LOCALES_BOOTSIER;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Offcanvas {
|
||||
id : OptionId,
|
||||
classes : OptionClasses,
|
||||
title : OptionTranslated,
|
||||
breakpoint: BreakPoint,
|
||||
placement : OffcanvasPlacement,
|
||||
visibility: OffcanvasVisibility,
|
||||
scrolling : OffcanvasBodyScroll,
|
||||
backdrop : OffcanvasBackdrop,
|
||||
children : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Offcanvas {
|
||||
fn new() -> Self {
|
||||
Offcanvas::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(
|
||||
ClassesOp::Prepend,
|
||||
[
|
||||
self.breakpoint().to_class("offcanvas"),
|
||||
self.placement().to_string(),
|
||||
self.visibility().to_string(),
|
||||
]
|
||||
.join(" "),
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let body = self.children().render(cx);
|
||||
if body.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
|
||||
let id = cx.required_id::<Self>(self.id());
|
||||
let id_label = join_string!(id, "-label");
|
||||
let id_target = join_string!("#", id);
|
||||
|
||||
let body_scroll = match self.body_scroll() {
|
||||
OffcanvasBodyScroll::Disabled => None,
|
||||
OffcanvasBodyScroll::Enabled => Some("true".to_string()),
|
||||
};
|
||||
|
||||
let backdrop = match self.backdrop() {
|
||||
OffcanvasBackdrop::Disabled => Some("true".to_string()),
|
||||
OffcanvasBackdrop::Enabled => None,
|
||||
OffcanvasBackdrop::Static => Some("static".to_string()),
|
||||
};
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
div
|
||||
id=(id)
|
||||
class=[self.classes().get()]
|
||||
tabindex="-1"
|
||||
data-bs-scroll=[body_scroll]
|
||||
data-bs-backdrop=[backdrop]
|
||||
aria-labelledby=(id_label)
|
||||
{
|
||||
div class="offcanvas-header" {
|
||||
h5 class="offcanvas-title" id=(id_label) {
|
||||
(self.title().escaped(cx.langid()))
|
||||
}
|
||||
button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="offcanvas"
|
||||
data-bs-target=(id_target)
|
||||
aria-label=[L10n::t("close", &LOCALES_BOOTSIER).using(cx.langid())]
|
||||
{}
|
||||
}
|
||||
div class="offcanvas-body" {
|
||||
(body)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Offcanvas {
|
||||
// Offcanvas BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_title(mut self, title: L10n) -> Self {
|
||||
self.title.alter_value(title);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self {
|
||||
self.breakpoint = bp;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_placement(mut self, placement: OffcanvasPlacement) -> Self {
|
||||
self.placement = placement;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_visibility(mut self, visibility: OffcanvasVisibility) -> Self {
|
||||
self.visibility = visibility;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_body_scroll(mut self, scrolling: OffcanvasBodyScroll) -> Self {
|
||||
self.scrolling = scrolling;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_backdrop(mut self, backdrop: OffcanvasBackdrop) -> Self {
|
||||
self.backdrop = backdrop;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_child(mut self, child: impl ComponentTrait) -> Self {
|
||||
self.children.add(Child::with(child));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_children(mut self, op: ChildOp) -> Self {
|
||||
self.children.alter_child(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Offcanvas GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn title(&self) -> &OptionTranslated {
|
||||
&self.title
|
||||
}
|
||||
|
||||
pub fn breakpoint(&self) -> &BreakPoint {
|
||||
&self.breakpoint
|
||||
}
|
||||
|
||||
pub fn placement(&self) -> &OffcanvasPlacement {
|
||||
&self.placement
|
||||
}
|
||||
|
||||
pub fn visibility(&self) -> &OffcanvasVisibility {
|
||||
&self.visibility
|
||||
}
|
||||
|
||||
pub fn body_scroll(&self) -> &OffcanvasBodyScroll {
|
||||
&self.scrolling
|
||||
}
|
||||
|
||||
pub fn backdrop(&self) -> &OffcanvasBackdrop {
|
||||
&self.backdrop
|
||||
}
|
||||
|
||||
pub fn children(&self) -> &Children {
|
||||
&self.children
|
||||
}
|
||||
}
|
||||
10
extensions/pagetop-bootsier/src/bs/utility.rs
Normal file
10
extensions/pagetop-bootsier/src/bs/utility.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
mod color;
|
||||
pub use color::Color;
|
||||
pub use color::{BgColor, BorderColor, TextColor};
|
||||
|
||||
mod opacity;
|
||||
pub use opacity::Opacity;
|
||||
pub use opacity::{BgOpacity, BorderOpacity, TextOpacity};
|
||||
|
||||
mod border;
|
||||
pub use border::{Border, BorderSize};
|
||||
102
extensions/pagetop-bootsier/src/bs/utility/border.rs
Normal file
102
extensions/pagetop-bootsier/src/bs/utility/border.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use pagetop::{prelude::*, strict_string};
|
||||
|
||||
use crate::bs::{BorderColor, BorderOpacity};
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BorderSize {
|
||||
#[default]
|
||||
Default,
|
||||
Zero,
|
||||
Width1,
|
||||
Width2,
|
||||
Width3,
|
||||
Width4,
|
||||
Width5,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BorderSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BorderSize::Default => write!(f, ""),
|
||||
BorderSize::Zero => write!(f, "0"),
|
||||
BorderSize::Width1 => write!(f, "1"),
|
||||
BorderSize::Width2 => write!(f, "2"),
|
||||
BorderSize::Width3 => write!(f, "3"),
|
||||
BorderSize::Width4 => write!(f, "4"),
|
||||
BorderSize::Width5 => write!(f, "5"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Border {
|
||||
color : BorderColor,
|
||||
opacity: BorderOpacity,
|
||||
size : BorderSize,
|
||||
top : BorderSize,
|
||||
end : BorderSize,
|
||||
bottom : BorderSize,
|
||||
start : BorderSize,
|
||||
}
|
||||
|
||||
impl Border {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn with(size: BorderSize) -> Self {
|
||||
Self::default().with_size(size)
|
||||
}
|
||||
|
||||
// Border BUILDER.
|
||||
|
||||
pub fn with_color(mut self, color: BorderColor) -> Self {
|
||||
self.color = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_opacity(mut self, opacity: BorderOpacity) -> Self {
|
||||
self.opacity = opacity;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_size(mut self, size: BorderSize) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_top(mut self, size: BorderSize) -> Self {
|
||||
self.top = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_end(mut self, size: BorderSize) -> Self {
|
||||
self.end = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_bottom(mut self, size: BorderSize) -> Self {
|
||||
self.bottom = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_start(mut self, size: BorderSize) -> Self {
|
||||
self.start = size;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for Border {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", strict_string!([
|
||||
"border",
|
||||
&self.color.to_string(),
|
||||
&self.opacity.to_string(),
|
||||
]; " ").unwrap_or_default())
|
||||
}
|
||||
}
|
||||
119
extensions/pagetop-bootsier/src/bs/utility/color.rs
Normal file
119
extensions/pagetop-bootsier/src/bs/utility/color.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Color {
|
||||
#[default]
|
||||
Primary,
|
||||
Secondary,
|
||||
Success,
|
||||
Info,
|
||||
Warning,
|
||||
Danger,
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Color::Primary => write!(f, "primary"),
|
||||
Color::Secondary => write!(f, "secondary"),
|
||||
Color::Success => write!(f, "success"),
|
||||
Color::Info => write!(f, "info"),
|
||||
Color::Warning => write!(f, "warning"),
|
||||
Color::Danger => write!(f, "danger"),
|
||||
Color::Light => write!(f, "light"),
|
||||
Color::Dark => write!(f, "dark"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BgColor {
|
||||
#[default]
|
||||
Default,
|
||||
Body,
|
||||
BodySecondary,
|
||||
BodyTertiary,
|
||||
Theme(Color),
|
||||
Subtle(Color),
|
||||
Black,
|
||||
White,
|
||||
Transparent,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BgColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BgColor::Default => write!(f, ""),
|
||||
BgColor::Body => write!(f, "bg-body"),
|
||||
BgColor::BodySecondary => write!(f, "bg-body-secondary"),
|
||||
BgColor::BodyTertiary => write!(f, "bg-body-tertiary"),
|
||||
BgColor::Theme(c) => write!(f, "bg-{}", c),
|
||||
BgColor::Subtle(c) => write!(f, "bg-{}-subtle", c),
|
||||
BgColor::Black => write!(f, "bg-black"),
|
||||
BgColor::White => write!(f, "bg-white"),
|
||||
BgColor::Transparent => write!(f, "bg-transparent"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BorderColor {
|
||||
#[default]
|
||||
Default,
|
||||
Theme(Color),
|
||||
Subtle(Color),
|
||||
Black,
|
||||
White,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BorderColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BorderColor::Default => write!(f, ""),
|
||||
BorderColor::Theme(c) => write!(f, "border-{}", c),
|
||||
BorderColor::Subtle(c) => write!(f, "border-{}-subtle", c),
|
||||
BorderColor::Black => write!(f, "border-black"),
|
||||
BorderColor::White => write!(f, "border-white"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum TextColor {
|
||||
#[default]
|
||||
Default,
|
||||
Body,
|
||||
BodyEmphasis,
|
||||
BodySecondary,
|
||||
BodyTertiary,
|
||||
Theme(Color),
|
||||
Emphasis(Color),
|
||||
Background(Color),
|
||||
Black,
|
||||
White,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for TextColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TextColor::Default => write!(f, ""),
|
||||
TextColor::Body => write!(f, "text-body"),
|
||||
TextColor::BodyEmphasis => write!(f, "text-body-emphasis"),
|
||||
TextColor::BodySecondary => write!(f, "text-body-secondary"),
|
||||
TextColor::BodyTertiary => write!(f, "text-body-tertiary"),
|
||||
TextColor::Theme(c) => write!(f, "text-{}", c),
|
||||
TextColor::Emphasis(c) => write!(f, "text-{}-emphasis", c),
|
||||
TextColor::Background(c) => write!(f, "text-bg-{}", c),
|
||||
TextColor::Black => write!(f, "text-black"),
|
||||
TextColor::White => write!(f, "text-white"),
|
||||
}
|
||||
}
|
||||
}
|
||||
78
extensions/pagetop-bootsier/src/bs/utility/opacity.rs
Normal file
78
extensions/pagetop-bootsier/src/bs/utility/opacity.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Opacity {
|
||||
#[default]
|
||||
Opaque, // 100%
|
||||
SemiOpaque, // 75%
|
||||
Half, // 50%
|
||||
SemiTransparent, // 25%
|
||||
AlmostTransparent, // 10%
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for Opacity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Opacity::Opaque => write!(f, "opacity-100"),
|
||||
Opacity::SemiOpaque => write!(f, "opacity-75"),
|
||||
Opacity::Half => write!(f, "opacity-50"),
|
||||
Opacity::SemiTransparent => write!(f, "opacity-25"),
|
||||
Opacity::AlmostTransparent => write!(f, "opacity-10"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BgOpacity {
|
||||
#[default]
|
||||
Default,
|
||||
Theme(Opacity),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BgOpacity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BgOpacity::Default => write!(f, ""),
|
||||
BgOpacity::Theme(o) => write!(f, "bg-{}", o),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BorderOpacity {
|
||||
#[default]
|
||||
Default,
|
||||
Theme(Opacity),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BorderOpacity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BorderOpacity::Default => write!(f, ""),
|
||||
BorderOpacity::Theme(o) => write!(f, "border-{}", o),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum TextOpacity {
|
||||
#[default]
|
||||
Default,
|
||||
Theme(Opacity),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for TextOpacity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TextOpacity::Default => write!(f, ""),
|
||||
TextOpacity::Theme(o) => write!(f, "text-{}", o),
|
||||
}
|
||||
}
|
||||
}
|
||||
116
extensions/pagetop-bootsier/src/bs/utility/rounded.rs
Normal file
116
extensions/pagetop-bootsier/src/bs/utility/rounded.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::{Color, Opacity};
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BorderSize {
|
||||
#[default]
|
||||
None,
|
||||
Width1,
|
||||
Width2,
|
||||
Width3,
|
||||
Width4,
|
||||
Width5,
|
||||
Free(unit::Value),
|
||||
}
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BorderRadius {
|
||||
#[default]
|
||||
None,
|
||||
Rounded1,
|
||||
Rounded2,
|
||||
Rounded3,
|
||||
Rounded4,
|
||||
Rounded5,
|
||||
Circle,
|
||||
Pill,
|
||||
Free(f32),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct BorderProperty {
|
||||
color : Color,
|
||||
opacity: Opacity,
|
||||
size : BorderSize,
|
||||
radius : BorderRadius,
|
||||
}
|
||||
|
||||
impl BorderProperty {
|
||||
pub fn new() -> Self {
|
||||
BorderProperty::default()
|
||||
}
|
||||
|
||||
pub fn with_color(mut self, color: Color) -> Self {
|
||||
self.color = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_opacity(mut self, opacity: Opacity) -> Self {
|
||||
self.opacity = opacity;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_size(mut self, size: BorderSize) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_radius(mut self, radius: BorderRadius) -> Self {
|
||||
self.radius = radius;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Border {
|
||||
all : Option<BorderProperty>,
|
||||
top : Option<BorderProperty>,
|
||||
end : Option<BorderProperty>,
|
||||
bottom: Option<BorderProperty>,
|
||||
start : Option<BorderProperty>,
|
||||
}
|
||||
|
||||
impl Border {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
// Border BUILDER.
|
||||
|
||||
pub fn with_all(mut self, border: BorderProperty) -> Self {
|
||||
self.all = Some(border);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_top(mut self, border: BorderProperty) -> Self {
|
||||
self.top = Some(border);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_end(mut self, border: BorderProperty) -> Self {
|
||||
self.end = Some(border);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_bottom(mut self, border: BorderProperty) -> Self {
|
||||
self.bottom = Some(border);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_start(mut self, border: BorderProperty) -> Self {
|
||||
self.start = Some(border);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_none(mut self) -> Self {
|
||||
self.all = None;
|
||||
self.top = None;
|
||||
self.end = None;
|
||||
self.bottom = None;
|
||||
self.start = None;
|
||||
self
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue