Revierte cambio "themes" por "layouts"

This commit is contained in:
Manuel Cillero 2024-12-19 20:56:17 +01:00
parent c379b37809
commit 53144eab91
31 changed files with 135 additions and 121 deletions

View file

@ -8,13 +8,13 @@ members = [
# PageTop # PageTop
"pagetop", "pagetop",
# Layouts
#"layouts/pagetop-aliner",
#"layouts/pagetop-bootsier",
# Packages # Packages
"packages/pagetop-seaorm", "packages/pagetop-seaorm",
# Themes
#"packages/pagetop-aliner",
#"packages/pagetop-bootsier",
# App # App
"drust", "drust",
] ]
@ -37,9 +37,9 @@ pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" }
# PageTop # PageTop
pagetop = { version = "0.0", path = "pagetop" } pagetop = { version = "0.0", path = "pagetop" }
# Layouts
#pagetop-aliner = { version = "0.0", path = "layouts/pagetop-aliner" }
#pagetop-bootsier = { version = "0.0", path = "layouts/pagetop-bootsier" }
# Packages # Packages
pagetop-seaorm = { version = "0.0", path = "packages/pagetop-seaorm" } pagetop-seaorm = { version = "0.0", path = "packages/pagetop-seaorm" }
# Themes
#pagetop-aliner = { version = "0.0", path = "packages/pagetop-aliner" }
#pagetop-bootsier = { version = "0.0", path = "packages/pagetop-bootsier" }

View file

@ -22,10 +22,10 @@ pueden implementar, extender o adaptar a las necesidades de cada solución web,
interceptando su flujo de ejecución. interceptando su flujo de ejecución.
* **Componentes** (*components*). Para encapsular HTML, CSS y JavaScript en unidades funcionales, * **Componentes** (*components*). Para encapsular HTML, CSS y JavaScript en unidades funcionales,
configurables y bien definidas. configurables y bien definidas.
* **Diseños** (*layouts*). Permiten a los desarrolladores modificar la apariencia de páginas y
componentes sin afectar a su funcionalidad.
* **Paquetes** (*packages*). Extienden o personalizan funcionalidades existentes interactuando con * **Paquetes** (*packages*). Extienden o personalizan funcionalidades existentes interactuando con
las APIs de `PageTop` o de paquetes de terceros. las APIs de `PageTop` o de paquetes de terceros.
* **Temas** (*themes*). Permiten a los desarrolladores modificar la apariencia de páginas y
componentes sin afectar a su funcionalidad.
# ⚡️ Guía rápida # ⚡️ Guía rápida

View file

@ -1,6 +1,6 @@
[app] [app]
#layout = "Aliner" #theme = "Aliner"
#layout = "Bootsier" #theme = "Bootsier"
language = "es-ES" language = "es-ES"
[log] [log]

View file

@ -1,8 +1,8 @@
[app] [app]
name = "My App" name = "My App"
description = "Developed with the amazing PageTop framework." description = "Developed with the amazing PageTop framework."
# Default layout. # Default theme.
layout = "Default" theme = "Default"
# Default language (localization). # Default language (localization).
language = "en-US" language = "en-US"
# Default text direction: "ltr", "rtl", or "auto". # Default text direction: "ltr", "rtl", or "auto".

View file

@ -23,13 +23,13 @@ struct Drust;
impl PackageTrait for Drust { impl PackageTrait for Drust {
fn dependencies(&self) -> Vec<PackageRef> { fn dependencies(&self) -> Vec<PackageRef> {
vec![ vec![
// Layouts.
//&pagetop_bootsier::Bootsier,
// Packages. // Packages.
//&pagetop_admin::Admin, //&pagetop_admin::Admin,
//&pagetop_user::User, //&pagetop_user::User,
//&pagetop_node::Node, //&pagetop_node::Node,
// Themes.
//&pagetop_bootsier::Bootsier,
] ]
} }
} }

View file

@ -4,6 +4,6 @@ pub mod action;
pub mod component; pub mod component;
pub mod layout;
pub mod package; pub mod package;
pub mod theme;

View file

@ -6,6 +6,6 @@ pub type FnActionWithPage = fn(page: &mut Page);
pub mod component; pub mod component;
pub mod layout; pub mod theme;
pub mod page; pub mod page;

View file

@ -4,13 +4,13 @@ use crate::base::action::FnActionWithComponent;
pub struct AfterRender<C: ComponentTrait> { pub struct AfterRender<C: ComponentTrait> {
f: FnActionWithComponent<C>, f: FnActionWithComponent<C>,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>,
} }
impl<C: ComponentTrait> ActionTrait for AfterRender<C> { impl<C: ComponentTrait> ActionTrait for AfterRender<C> {
fn layout_type_id(&self) -> Option<UniqueId> { fn theme_type_id(&self) -> Option<UniqueId> {
self.layout_type_id self.theme_type_id
} }
fn referer_type_id(&self) -> Option<UniqueId> { fn referer_type_id(&self) -> Option<UniqueId> {
@ -19,10 +19,10 @@ impl<C: ComponentTrait> ActionTrait for AfterRender<C> {
} }
impl<C: ComponentTrait> AfterRender<C> { impl<C: ComponentTrait> AfterRender<C> {
pub fn new(layout: LayoutRef, f: FnActionWithComponent<C>) -> Self { pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self {
AfterRender { AfterRender {
f, f,
layout_type_id: Some(layout.type_id()), theme_type_id: Some(theme.type_id()),
referer_type_id: Some(UniqueId::of::<C>()), referer_type_id: Some(UniqueId::of::<C>()),
} }
} }
@ -33,7 +33,7 @@ impl<C: ComponentTrait> AfterRender<C> {
dispatch_actions( dispatch_actions(
&ActionKey::new( &ActionKey::new(
UniqueId::of::<Self>(), UniqueId::of::<Self>(),
Some(cx.layout().type_id()), Some(cx.theme().type_id()),
Some(UniqueId::of::<C>()), Some(UniqueId::of::<C>()),
None, None,
), ),

View file

@ -4,20 +4,20 @@ use crate::base::action::FnActionWithPage;
pub struct AfterRenderBody { pub struct AfterRenderBody {
f: FnActionWithPage, f: FnActionWithPage,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
} }
impl ActionTrait for AfterRenderBody { impl ActionTrait for AfterRenderBody {
fn layout_type_id(&self) -> Option<UniqueId> { fn theme_type_id(&self) -> Option<UniqueId> {
self.layout_type_id self.theme_type_id
} }
} }
impl AfterRenderBody { impl AfterRenderBody {
pub fn new(layout: LayoutRef, f: FnActionWithPage) -> Self { pub fn new(theme: ThemeRef, f: FnActionWithPage) -> Self {
AfterRenderBody { AfterRenderBody {
f, f,
layout_type_id: Some(layout.type_id()), theme_type_id: Some(theme.type_id()),
} }
} }
@ -27,7 +27,7 @@ impl AfterRenderBody {
dispatch_actions( dispatch_actions(
&ActionKey::new( &ActionKey::new(
UniqueId::of::<Self>(), UniqueId::of::<Self>(),
Some(page.context().layout().type_id()), Some(page.context().theme().type_id()),
None, None,
None, None,
), ),

View file

@ -4,13 +4,13 @@ use crate::base::action::FnActionWithComponent;
pub struct BeforeRender<C: ComponentTrait> { pub struct BeforeRender<C: ComponentTrait> {
f: FnActionWithComponent<C>, f: FnActionWithComponent<C>,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>,
} }
impl<C: ComponentTrait> ActionTrait for BeforeRender<C> { impl<C: ComponentTrait> ActionTrait for BeforeRender<C> {
fn layout_type_id(&self) -> Option<UniqueId> { fn theme_type_id(&self) -> Option<UniqueId> {
self.layout_type_id self.theme_type_id
} }
fn referer_type_id(&self) -> Option<UniqueId> { fn referer_type_id(&self) -> Option<UniqueId> {
@ -19,10 +19,10 @@ impl<C: ComponentTrait> ActionTrait for BeforeRender<C> {
} }
impl<C: ComponentTrait> BeforeRender<C> { impl<C: ComponentTrait> BeforeRender<C> {
pub fn new(layout: LayoutRef, f: FnActionWithComponent<C>) -> Self { pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self {
BeforeRender { BeforeRender {
f, f,
layout_type_id: Some(layout.type_id()), theme_type_id: Some(theme.type_id()),
referer_type_id: Some(UniqueId::of::<C>()), referer_type_id: Some(UniqueId::of::<C>()),
} }
} }
@ -33,7 +33,7 @@ impl<C: ComponentTrait> BeforeRender<C> {
dispatch_actions( dispatch_actions(
&ActionKey::new( &ActionKey::new(
UniqueId::of::<Self>(), UniqueId::of::<Self>(),
Some(cx.layout().type_id()), Some(cx.theme().type_id()),
Some(UniqueId::of::<C>()), Some(UniqueId::of::<C>()),
None, None,
), ),

View file

@ -4,20 +4,20 @@ use crate::base::action::FnActionWithPage;
pub struct BeforeRenderBody { pub struct BeforeRenderBody {
f: FnActionWithPage, f: FnActionWithPage,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
} }
impl ActionTrait for BeforeRenderBody { impl ActionTrait for BeforeRenderBody {
fn layout_type_id(&self) -> Option<UniqueId> { fn theme_type_id(&self) -> Option<UniqueId> {
self.layout_type_id self.theme_type_id
} }
} }
impl BeforeRenderBody { impl BeforeRenderBody {
pub fn new(layout: LayoutRef, f: FnActionWithPage) -> Self { pub fn new(theme: ThemeRef, f: FnActionWithPage) -> Self {
BeforeRenderBody { BeforeRenderBody {
f, f,
layout_type_id: Some(layout.type_id()), theme_type_id: Some(theme.type_id()),
} }
} }
@ -27,7 +27,7 @@ impl BeforeRenderBody {
dispatch_actions( dispatch_actions(
&ActionKey::new( &ActionKey::new(
UniqueId::of::<Self>(), UniqueId::of::<Self>(),
Some(page.context().layout().type_id()), Some(page.context().theme().type_id()),
None, None,
None, None,
), ),

View file

@ -4,13 +4,13 @@ pub type FnRenderComponent<C> = fn(component: &C, cx: &mut Context) -> Option<Ma
pub struct RenderComponent<C: ComponentTrait> { pub struct RenderComponent<C: ComponentTrait> {
f: FnRenderComponent<C>, f: FnRenderComponent<C>,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>,
} }
impl<C: ComponentTrait> ActionTrait for RenderComponent<C> { impl<C: ComponentTrait> ActionTrait for RenderComponent<C> {
fn layout_type_id(&self) -> Option<UniqueId> { fn theme_type_id(&self) -> Option<UniqueId> {
self.layout_type_id self.theme_type_id
} }
fn referer_type_id(&self) -> Option<UniqueId> { fn referer_type_id(&self) -> Option<UniqueId> {
@ -19,10 +19,10 @@ impl<C: ComponentTrait> ActionTrait for RenderComponent<C> {
} }
impl<C: ComponentTrait> RenderComponent<C> { impl<C: ComponentTrait> RenderComponent<C> {
pub fn new(layout: LayoutRef, f: FnRenderComponent<C>) -> Self { pub fn new(theme: ThemeRef, f: FnRenderComponent<C>) -> Self {
RenderComponent { RenderComponent {
f, f,
layout_type_id: Some(layout.type_id()), theme_type_id: Some(theme.type_id()),
referer_type_id: Some(UniqueId::of::<C>()), referer_type_id: Some(UniqueId::of::<C>()),
} }
} }
@ -34,7 +34,7 @@ impl<C: ComponentTrait> RenderComponent<C> {
dispatch_actions( dispatch_actions(
&ActionKey::new( &ActionKey::new(
UniqueId::of::<Self>(), UniqueId::of::<Self>(),
Some(cx.layout().type_id()), Some(cx.theme().type_id()),
Some(UniqueId::of::<C>()), Some(UniqueId::of::<C>()),
None, None,
), ),

View file

@ -19,7 +19,7 @@ impl PackageTrait for Welcome {
async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.with_title(L10n::l("welcome_page")) .with_title(L10n::l("welcome_page"))
.with_assets(AssetsOp::Layout("Basic")) .with_assets(AssetsOp::Theme("Basic"))
.with_assets(AssetsOp::AddStyleSheet(StyleSheet::inline("styles", r##" .with_assets(AssetsOp::AddStyleSheet(StyleSheet::inline("styles", r##"
body { body {
background-color: #f3d060; background-color: #f3d060;

View file

@ -3,9 +3,9 @@ use crate::prelude::*;
pub struct Basic; pub struct Basic;
impl PackageTrait for Basic { impl PackageTrait for Basic {
fn layout(&self) -> Option<LayoutRef> { fn theme(&self) -> Option<ThemeRef> {
Some(&Basic) Some(&Basic)
} }
} }
impl LayoutTrait for Basic {} impl ThemeTrait for Basic {}

View file

@ -80,8 +80,8 @@ pub mod action;
// API to build new components. // API to build new components.
pub mod component; pub mod component;
// API to add new layouts.
pub mod layout;
// API to add new features with packages. // API to add new features with packages.
pub mod package; pub mod package;
// API to add new themes.
pub mod theme;

View file

@ -6,7 +6,7 @@ pub type ActionBox = Box<dyn ActionTrait>;
#[derive(Eq, PartialEq, Hash)] #[derive(Eq, PartialEq, Hash)]
pub struct ActionKey { pub struct ActionKey {
action_type_id: UniqueId, action_type_id: UniqueId,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>,
referer_id: Option<String>, referer_id: Option<String>,
} }
@ -14,13 +14,13 @@ pub struct ActionKey {
impl ActionKey { impl ActionKey {
pub fn new( pub fn new(
action_type_id: UniqueId, action_type_id: UniqueId,
layout_type_id: Option<UniqueId>, theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>,
referer_id: Option<String>, referer_id: Option<String>,
) -> Self { ) -> Self {
ActionKey { ActionKey {
action_type_id, action_type_id,
layout_type_id, theme_type_id,
referer_type_id, referer_type_id,
referer_id, referer_id,
} }
@ -32,7 +32,7 @@ pub trait ActionBase {
} }
pub trait ActionTrait: ActionBase + AnyBase + Send + Sync { pub trait ActionTrait: ActionBase + AnyBase + Send + Sync {
fn layout_type_id(&self) -> Option<UniqueId> { fn theme_type_id(&self) -> Option<UniqueId> {
None None
} }
@ -53,7 +53,7 @@ impl<A: ActionTrait> ActionBase for A {
fn key(&self) -> ActionKey { fn key(&self) -> ActionKey {
ActionKey { ActionKey {
action_type_id: self.type_id(), action_type_id: self.type_id(),
layout_type_id: self.layout_type_id(), theme_type_id: self.theme_type_id(),
referer_type_id: self.referer_type_id(), referer_type_id: self.referer_type_id(),
referer_id: self.referer_id(), referer_id: self.referer_id(),
} }

View file

@ -1,6 +1,6 @@
use crate::core::component::ChildOp; use crate::core::component::ChildOp;
use crate::core::layout::all::{layout_by_short_name, DEFAULT_LAYOUT}; use crate::core::theme::all::{theme_by_short_name, DEFAULT_THEME};
use crate::core::layout::{ChildrenInRegions, LayoutRef}; use crate::core::theme::{ChildrenInRegions, ThemeRef};
use crate::html::{html, Markup}; use crate::html::{html, Markup};
use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
use crate::locale::{LanguageIdentifier, DEFAULT_LANGID}; use crate::locale::{LanguageIdentifier, DEFAULT_LANGID};
@ -17,6 +17,7 @@ use std::fmt;
pub enum AssetsOp { pub enum AssetsOp {
LangId(&'static LanguageIdentifier), LangId(&'static LanguageIdentifier),
Theme(&'static str),
Layout(&'static str), Layout(&'static str),
// Favicon. // Favicon.
SetFavicon(Option<Favicon>), SetFavicon(Option<Favicon>),
@ -50,7 +51,8 @@ impl Error for ErrorParam {}
pub struct Context { pub struct Context {
request : HttpRequest, request : HttpRequest,
langid : &'static LanguageIdentifier, langid : &'static LanguageIdentifier,
layout : LayoutRef, theme : ThemeRef,
layout : &'static str,
favicon : Option<Favicon>, favicon : Option<Favicon>,
stylesheet: Assets<StyleSheet>, stylesheet: Assets<StyleSheet>,
javascript: Assets<JavaScript>, javascript: Assets<JavaScript>,
@ -65,7 +67,8 @@ impl Context {
Context { Context {
request, request,
langid : &DEFAULT_LANGID, langid : &DEFAULT_LANGID,
layout : *DEFAULT_LAYOUT, theme : *DEFAULT_THEME,
layout : "default",
favicon : None, favicon : None,
stylesheet: Assets::<StyleSheet>::new(), stylesheet: Assets::<StyleSheet>::new(),
javascript: Assets::<JavaScript>::new(), javascript: Assets::<JavaScript>::new(),
@ -80,8 +83,11 @@ impl Context {
AssetsOp::LangId(langid) => { AssetsOp::LangId(langid) => {
self.langid = langid; self.langid = langid;
} }
AssetsOp::Layout(layout_name) => { AssetsOp::Theme(theme_name) => {
self.layout = layout_by_short_name(layout_name).unwrap_or(*DEFAULT_LAYOUT); self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME);
}
AssetsOp::Layout(layout) => {
self.layout = layout;
} }
// Favicon. // Favicon.
AssetsOp::SetFavicon(favicon) => { AssetsOp::SetFavicon(favicon) => {
@ -134,7 +140,11 @@ impl Context {
self.langid self.langid
} }
pub fn layout(&self) -> LayoutRef { pub fn theme(&self) -> ThemeRef {
self.theme
}
pub fn layout(&self) -> &str {
self.layout self.layout
} }
@ -163,7 +173,7 @@ impl Context {
pub fn render_region(&mut self, region: impl Into<String>) -> Markup { pub fn render_region(&mut self, region: impl Into<String>) -> Markup {
self.regions self.regions
.all_in_region(self.layout, &region.into()) .all_in_region(self.theme, &region.into())
.render(self) .render(self)
} }

View file

@ -41,19 +41,19 @@ impl<C: ComponentTrait> ComponentBase for C {
self.setup_before_prepare(cx); self.setup_before_prepare(cx);
// Acciones específicas del diseño antes de renderizar el componente. // Acciones específicas del diseño antes de renderizar el componente.
action::layout::BeforeRender::dispatch(self, cx); action::theme::BeforeRender::dispatch(self, cx);
// Acciones de los paquetes antes de renderizar el componente. // Acciones de los paquetes antes de renderizar el componente.
action::component::BeforeRender::dispatch(self, cx); action::component::BeforeRender::dispatch(self, cx);
// Renderiza el componente. // Renderiza el componente.
let markup = match action::layout::RenderComponent::dispatch(self, cx) { let markup = match action::theme::RenderComponent::dispatch(self, cx) {
Some(html) => html, Some(html) => html,
None => self.prepare_component(cx).render(), None => self.prepare_component(cx).render(),
}; };
// Acciones específicas del diseño después de renderizar el componente. // Acciones específicas del diseño después de renderizar el componente.
action::layout::AfterRender::dispatch(self, cx); action::theme::AfterRender::dispatch(self, cx);
// Acciones de los paquetes después de renderizar el componente. // Acciones de los paquetes después de renderizar el componente.
action::component::AfterRender::dispatch(self, cx); action::component::AfterRender::dispatch(self, cx);

View file

@ -1,6 +1,6 @@
use crate::core::action::add_action; use crate::core::action::add_action;
use crate::core::layout::all::LAYOUTS;
use crate::core::package::PackageRef; use crate::core::package::PackageRef;
use crate::core::theme::all::THEMES;
use crate::{global, include_files, include_files_service, service, trace}; use crate::{global, include_files, include_files_service, service, trace};
use std::sync::{LazyLock, RwLock}; use std::sync::{LazyLock, RwLock};
@ -19,8 +19,8 @@ pub fn register_packages(root_package: Option<PackageRef>) {
// Initialize a list for packages to be enabled. // Initialize a list for packages to be enabled.
let mut enabled_list: Vec<PackageRef> = Vec::new(); let mut enabled_list: Vec<PackageRef> = Vec::new();
// Add default layout to the enabled list. // Add default theme to the enabled list.
add_to_enabled(&mut enabled_list, &crate::base::layout::Basic); add_to_enabled(&mut enabled_list, &crate::base::theme::Basic);
// If a root package is provided, add it to the enabled list. // If a root package is provided, add it to the enabled list.
if let Some(package) = root_package { if let Some(package) = root_package {
@ -54,16 +54,16 @@ fn add_to_enabled(list: &mut Vec<PackageRef>, package: PackageRef) {
// Add the package itself to the enabled list. // Add the package itself to the enabled list.
list.push(package); list.push(package);
// Check if the package has an associated layout to register. // Check if the package has an associated theme to register.
if let Some(layout) = package.layout() { if let Some(theme) = package.theme() {
let mut registered_layouts = LAYOUTS.write().unwrap(); let mut registered_themes = THEMES.write().unwrap();
// Ensure the layout is not already registered to avoid duplicates. // Ensure the theme is not already registered to avoid duplicates.
if !registered_layouts if !registered_themes
.iter() .iter()
.any(|t| t.type_id() == layout.type_id()) .any(|t| t.type_id() == theme.type_id())
{ {
registered_layouts.push(layout); registered_themes.push(theme);
trace::debug!("Enabling \"{}\" layout", layout.short_name()); trace::debug!("Enabling \"{}\" theme", theme.short_name());
} }
} else { } else {
trace::debug!("Enabling \"{}\" package", package.short_name()); trace::debug!("Enabling \"{}\" package", package.short_name());

View file

@ -1,5 +1,5 @@
use crate::core::action::ActionBox; use crate::core::action::ActionBox;
use crate::core::layout::LayoutRef; use crate::core::theme::ThemeRef;
use crate::core::AnyBase; use crate::core::AnyBase;
use crate::locale::L10n; use crate::locale::L10n;
use crate::{actions, service}; use crate::{actions, service};
@ -16,7 +16,7 @@ pub trait PackageTrait: AnyBase + Send + Sync {
L10n::default() L10n::default()
} }
fn layout(&self) -> Option<LayoutRef> { fn theme(&self) -> Option<ThemeRef> {
None None
} }

View file

@ -1,5 +1,5 @@
mod definition; mod definition;
pub use definition::{LayoutRef, LayoutTrait}; pub use definition::{ThemeRef, ThemeTrait};
mod regions; mod regions;
pub(crate) use regions::ChildrenInRegions; pub(crate) use regions::ChildrenInRegions;

View file

@ -1,33 +1,31 @@
use crate::core::layout::LayoutRef; use crate::core::theme::ThemeRef;
use crate::global; use crate::global;
use std::sync::{LazyLock, RwLock}; use std::sync::{LazyLock, RwLock};
// THEMES ****************************************************************************************** // THEMES ******************************************************************************************
pub static LAYOUTS: LazyLock<RwLock<Vec<LayoutRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); pub static THEMES: LazyLock<RwLock<Vec<ThemeRef>>> = LazyLock::new(|| RwLock::new(Vec::new()));
// DEFAULT THEME *********************************************************************************** // DEFAULT THEME ***********************************************************************************
pub static DEFAULT_LAYOUT: LazyLock<LayoutRef> = pub static DEFAULT_THEME: LazyLock<ThemeRef> =
LazyLock::new( LazyLock::new(|| match theme_by_short_name(&global::SETTINGS.app.theme) {
|| match layout_by_short_name(&global::SETTINGS.app.layout) { Some(theme) => theme,
Some(layout) => layout, None => &crate::base::theme::Basic,
None => &crate::base::layout::Basic, });
},
);
// THEME BY NAME *********************************************************************************** // THEME BY NAME ***********************************************************************************
pub fn layout_by_short_name(short_name: &str) -> Option<LayoutRef> { pub fn theme_by_short_name(short_name: &str) -> Option<ThemeRef> {
let short_name = short_name.to_lowercase(); let short_name = short_name.to_lowercase();
match LAYOUTS match THEMES
.read() .read()
.unwrap() .unwrap()
.iter() .iter()
.find(|t| t.short_name().to_lowercase() == short_name) .find(|t| t.short_name().to_lowercase() == short_name)
{ {
Some(layout) => Some(*layout), Some(theme) => Some(*theme),
_ => None, _ => None,
} }
} }

View file

@ -4,10 +4,10 @@ use crate::html::{html, Markup};
use crate::locale::L10n; use crate::locale::L10n;
use crate::response::page::Page; use crate::response::page::Page;
pub type LayoutRef = &'static dyn LayoutTrait; pub type ThemeRef = &'static dyn ThemeTrait;
/// Los diseños deben implementar este "trait". /// Los diseños deben implementar este "trait".
pub trait LayoutTrait: PackageTrait + Send + Sync { pub trait ThemeTrait: PackageTrait + Send + Sync {
fn regions(&self) -> Vec<(&'static str, L10n)> { fn regions(&self) -> Vec<(&'static str, L10n)> {
vec![("content", L10n::l("content"))] vec![("content", L10n::l("content"))]
} }

View file

@ -1,11 +1,11 @@
use crate::core::component::{ChildComponent, ChildOp, Children}; use crate::core::component::{ChildComponent, ChildOp, Children};
use crate::core::layout::LayoutRef; use crate::core::theme::ThemeRef;
use crate::{fn_builder, AutoDefault, UniqueId}; use crate::{fn_builder, AutoDefault, UniqueId};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{LazyLock, RwLock}; use std::sync::{LazyLock, RwLock};
static LAYOUT_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> = static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> =
LazyLock::new(|| RwLock::new(HashMap::new())); LazyLock::new(|| RwLock::new(HashMap::new()));
static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> =
@ -33,9 +33,9 @@ impl ChildrenInRegions {
self self
} }
pub fn all_in_region(&self, layout: LayoutRef, region: &str) -> Children { pub fn all_in_region(&self, theme: ThemeRef, region: &str) -> Children {
let common = COMMON_REGIONS.read().unwrap(); let common = COMMON_REGIONS.read().unwrap();
if let Some(r) = LAYOUT_REGIONS.read().unwrap().get(&layout.type_id()) { if let Some(r) = THEME_REGIONS.read().unwrap().get(&theme.type_id()) {
Children::merge(&[common.0.get(region), self.0.get(region), r.0.get(region)]) Children::merge(&[common.0.get(region), self.0.get(region), r.0.get(region)])
} else { } else {
Children::merge(&[common.0.get(region), self.0.get(region)]) Children::merge(&[common.0.get(region), self.0.get(region)])
@ -46,7 +46,7 @@ impl ChildrenInRegions {
pub enum InRegion { pub enum InRegion {
Content, Content,
Named(&'static str), Named(&'static str),
OfLayout(&'static str, LayoutRef), OfTheme(&'static str, ThemeRef),
} }
impl InRegion { impl InRegion {
@ -64,12 +64,12 @@ impl InRegion {
.unwrap() .unwrap()
.alter_in_region(name, ChildOp::Add(child)); .alter_in_region(name, ChildOp::Add(child));
} }
InRegion::OfLayout(region, layout) => { InRegion::OfTheme(region, theme) => {
let mut regions = LAYOUT_REGIONS.write().unwrap(); let mut regions = THEME_REGIONS.write().unwrap();
if let Some(r) = regions.get_mut(&layout.type_id()) { if let Some(r) = regions.get_mut(&theme.type_id()) {
r.alter_in_region(region, ChildOp::Add(child)); r.alter_in_region(region, ChildOp::Add(child));
} else { } else {
regions.insert(layout.type_id(), ChildrenInRegions::with(region, child)); regions.insert(theme.type_id(), ChildrenInRegions::with(region, child));
} }
} }
} }

View file

@ -8,7 +8,7 @@ include_config!(SETTINGS: Settings => [
// [app] // [app]
"app.name" => "My App", "app.name" => "My App",
"app.description" => "Developed with the amazing PageTop framework.", "app.description" => "Developed with the amazing PageTop framework.",
"app.layout" => "", "app.theme" => "",
"app.language" => "en-US", "app.language" => "en-US",
"app.text_direction" => "ltr", "app.text_direction" => "ltr",
"app.startup_banner" => "Slant", "app.startup_banner" => "Slant",
@ -50,9 +50,9 @@ pub struct App {
/// A brief description of the application. /// A brief description of the application.
/// Default: *"Developed with the amazing PageTop framework."*. /// Default: *"Developed with the amazing PageTop framework."*.
pub description: String, pub description: String,
/// Default layout. /// Default theme.
/// Default: *""*. /// Default: *""*.
pub layout: String, pub theme: String,
/// Default language (localization). /// Default language (localization).
/// Default: *"en-US"*. /// Default: *"en-US"*.
pub language: String, pub language: String,

View file

@ -1,7 +1,7 @@
//! **OptionClasses** implements a *helper* for dynamically adding class names to components. //! **OptionClasses** implements a *helper* for dynamically adding class names to components.
//! //!
//! This *helper* differentiates between default classes (generally associated with styles provided //! This *helper* differentiates between default classes (generally associated with styles provided
//! by the layout) and user classes (for customizing components based on application styles). //! by the theme) and user classes (for customizing components based on application styles).
//! //!
//! Classes can be added using [Add]. Operations to [Remove], [Replace] or [Toggle] a class, as well //! Classes can be added using [Add]. Operations to [Remove], [Replace] or [Toggle] a class, as well
//! as [Clear] all classes, are also provided. //! as [Clear] all classes, are also provided.

View file

@ -23,10 +23,10 @@
//! comportamiento interno interceptando su flujo de ejecución. //! comportamiento interno interceptando su flujo de ejecución.
//! * **Componentes** (*components*). Para encapsular HTML, CSS y JavaScript en unidades //! * **Componentes** (*components*). Para encapsular HTML, CSS y JavaScript en unidades
//! funcionales, configurables y bien definidas. //! funcionales, configurables y bien definidas.
//! * **Diseños** (*layouts*). Permiten a los desarrolladores modificar la apariencia de páginas y
//! componentes sin afectar a su funcionalidad.
//! * **Paquetes** (*packages*). Extienden o personalizan funcionalidades existentes interactuando //! * **Paquetes** (*packages*). Extienden o personalizan funcionalidades existentes interactuando
//! con las APIs de `PageTop` o de paquetes de terceros. //! con las APIs de `PageTop` o de paquetes de terceros.
//! * **Temas** (*themes*). Permiten a los desarrolladores modificar la apariencia de páginas y
//! componentes sin afectar a su funcionalidad.
//! //!
//! # ⚡️ Guía rápida //! # ⚡️ Guía rápida
//! //!

View file

@ -40,13 +40,13 @@ pub use crate::core::{AnyBase, AnyTo};
pub use crate::core::action::*; pub use crate::core::action::*;
pub use crate::core::component::*; pub use crate::core::component::*;
pub use crate::core::layout::*;
pub use crate::core::package::*; pub use crate::core::package::*;
pub use crate::core::theme::*;
pub use crate::response::{json::*, page::*, redirect::*, ResponseError}; pub use crate::response::{json::*, page::*, redirect::*, ResponseError};
pub use crate::base::action; pub use crate::base::action;
pub use crate::base::component::*; pub use crate::base::component::*;
pub use crate::base::layout; pub use crate::base::theme;
pub use crate::app::Application; pub use crate::app::Application;

View file

@ -91,6 +91,12 @@ impl Page {
self self
} }
#[fn_builder]
pub fn alter_theme(&mut self, theme: &'static str) -> &mut Self {
self.context.alter_assets(AssetsOp::Theme(theme));
self
}
#[fn_builder] #[fn_builder]
pub fn alter_layout(&mut self, layout: &'static str) -> &mut Self { pub fn alter_layout(&mut self, layout: &'static str) -> &mut Self {
self.context.alter_assets(AssetsOp::Layout(layout)); self.context.alter_assets(AssetsOp::Layout(layout));
@ -157,22 +163,22 @@ impl Page {
pub fn render(&mut self) -> ResultPage<Markup, ErrorPage> { pub fn render(&mut self) -> ResultPage<Markup, ErrorPage> {
// Acciones específicas del diseño antes de renderizar el <body>. // Acciones específicas del diseño antes de renderizar el <body>.
action::layout::BeforeRenderBody::dispatch(self); action::theme::BeforeRenderBody::dispatch(self);
// Acciones de los paquetes antes de renderizar el <body>. // Acciones de los paquetes antes de renderizar el <body>.
action::page::BeforeRenderBody::dispatch(self); action::page::BeforeRenderBody::dispatch(self);
// Renderiza el <body>. // Renderiza el <body>.
let body = self.context.layout().render_body(self); let body = self.context.theme().render_body(self);
// Acciones específicas del diseño después de renderizar el <body>. // Acciones específicas del diseño después de renderizar el <body>.
action::layout::AfterRenderBody::dispatch(self); action::theme::AfterRenderBody::dispatch(self);
// Acciones de los paquetes después de renderizar el <body>. // Acciones de los paquetes después de renderizar el <body>.
action::page::AfterRenderBody::dispatch(self); action::page::AfterRenderBody::dispatch(self);
// Renderiza el <head>. // Renderiza el <head>.
let head = self.context.layout().render_head(self); let head = self.context.theme().render_head(self);
// Compone la página completa incluyendo los atributos de idioma y dirección del texto. // Compone la página completa incluyendo los atributos de idioma y dirección del texto.
let lang = &self.context.langid().language; let lang = &self.context.langid().language;