Commit graph

147 commits

Author SHA1 Message Date
346714ab29 ✨ (pagetop): Mejora la elección de zona horaria
- Nuevas opciones `app.timezone_regions`, `app.timezone_order` y
  `app.timezone_per_user` para limitar y ordenar las regiones ofrecidas
  y decidir si cada usuario puede tener su propia zona horaria.
- Añade `TzRegion` y `TimezoneOrder`; `Timezone::supported_by_region()`
  devuelve ahora `TzRegion` y excluye los alias de la base IANA que
  repiten otra zona (tzdata 2025b).
- Añade `Timezone::is_supported_in()` para validar con otras regiones.
- `SelectTimezone` admite `with_regions()`, `with_order()` y
  `with_utc_offset()`, muestra nombres legibles y conserva la zona
  actual aunque ya no se ofrezca.
- `app.timezone` se resuelve sin distinguir mayúsculas.
- pagetop-user no ofrece idioma ni zona horaria si no se aplican y
  conserva lo guardado; acepta la zona actual aunque ya no se ofrezca.
2026-10-07 01:20:47 +02:00
70744a51a5 ✨ (auth): Añade idioma y tema preferidos al usuario
- CurrentUser pasa de enum a struct con `id` opcional (anónimo = None) y
  preferencias de idioma, zona horaria y tema validadas en `with_*()`.
- `RequestLocale` tiene en cuenta el idioma preferido del usuario, y
  Context usa su tema si lo tiene (`default_theme()` en otro caso).
- Nuevos componentes `form::SelectLanguage`, `form::SelectTheme` y
  `form::SelectTimezone`, con `Timezone::supported_by_region()` para
  listar y validar las zonas IANA ofrecidas.
2026-10-04 23:09:07 +02:00
c848b97450 🎨 (basic): Organiza estilos de Basic e Intro
Divide `basic.css` en parciales SCSS bajo `assets/scss/basic/`, integra
`normalize.css` en `basic.min.css` y compila `intro.scss` por separado a
`intro.min.css`.
2026-10-03 11:15:10 +02:00
56a2471090 💄 (button): Aplica estilo deshabilitado a enlaces
Un `<a>` deshabilitado no tiene un equivalente a `:disabled` sobre el
que aplicar estilos. Button añade ahora la clase `disabled`.
2026-10-02 23:33:22 +02:00
c06efbd0d1 🎨 Ajustes menores de separadores de sección 2026-10-02 22:59:26 +02:00
165cb49880 ✨ (base): Añade with_menu_end() para menú al final 2026-09-26 14:21:39 +02:00
3f3634fdab ♻️ Atributos class e id explícitos en html!
Se usa `class="..."` e `id="..."` en lugar de `div.a #x`. El HTML
generado es idéntico.
2026-09-26 07:05:59 +02:00
58d1fef4f1 ⚡️ (core): Registro de acciones inmutable 2026-09-26 00:56:30 +02:00
5b2ddeb6cc ⚡️ (pagetop): Mejora uso de Props, Grid y HttpRequest 2026-09-24 22:29:27 +02:00
c47724bb68 ✨ (base): Implementa Navbar con funcionalidad base
Añade `Navbar::with_position()` y `navbar::Position` al núcleo, con las
clases de Basic para barras fijas y pegajosas, y `navbar::Item::form()`
para mostrar un formulario dentro de la barra.

Las barras sin botón de despliegue (`Simple` y `SimpleBrandLeft`) ya no
colapsan: el punto de corte no les afecta y su menú se mantiene en
línea, con salto de línea si no cabe. En Bootsier usan `navbar-expand` y
`SimpleBrandLeft` agrupa los contenidos junto a la marca.
2026-09-21 16:27:44 +02:00
f8f023b513 ✨ (pagetop): Añade PageTopSvg::Tile y ajusta Image 2026-09-21 13:51:18 +02:00
16eec316c4 ♻️ (base): Reorganiza el componente Intro 2026-09-20 23:53:18 +02:00
c6cd4fcd7d ✨ (base): Añade with_width() a Container 2026-09-19 03:14:21 +02:00
9143f1eb26 ✨ (pagetop): Añade with_expand() a Navbar
Navbar guarda el punto de corte a partir del cual deja de colapsar
(`Breakpoint::Md` por defecto) y añade la clase `navbar-expand-{nombre}`
o `navbar-expand` si no tiene ancho mínimo. El nombre lo resuelve el
tema activo con `Theme::breakpoint_entry()`.
2026-09-19 01:52:55 +02:00
307ca6f62c ✨ (pagetop): Añade Grid y extrae Flex de Container 2026-09-18 16:49:09 +02:00
3c3ffc91e6 ♻️ (pagetop): with_prop() acepta impl Into<PropsOp>
`FlexItem`, `Margin` y `Padding` se pasan directamente gracias a `From`
 hacia `PropsOp`, sin `PropsOp::flex_item()`/`margin()`/`padding()` ni
`.into()` explícito. Revisadas todas las llamadas en el código para
simplificarlas.
2026-09-13 01:38:33 +02:00
64113aff09 ♻️ (pagetop): Sustituye StyleSheet::inline
- `StyleSheet::inline` se resuelve ahora con `ResponsiveStyles`.
- `StyleSheet` se simplifica a sólo hojas de estilo externas.
- `ResponsiveStyles` añade `add_styles()` para declarar varias
  propiedades en una sola llamada.
- `AssetsOp` gana un constructor por variante y conversiones
  "From<Favicon/Preload/StyleSheet/JavaScript>" para pasarlos
  directamente a `with_assets()`.
2026-09-12 20:44:17 +02:00
0b8f3f3000 ✨ (pagetop): Añade puntos de corte a Flex/FlexItem
- `Breakpoint` gana variante `Xxxl` y métodos `name()`/`min_width()`/
  `resolved()`, para consultarse contra el tema activo.
- `Theme::breakpoint_entry()` sustituye a `breakpoint_min_width()`:
  devuelve un `BreakpointEntry` con nombre y ancho mínimo.
- Nuevo `Responsive<T>`, valor en cascada mobile-first por punto de
  corte.
- Ejemplo `examples/intro-responsive.rs` con los patrones de uso.
2026-09-12 11:13:19 +02:00
8577ca8a59 ♻️ (pagetop): Props::unpack() exige &mut Context 2026-09-08 07:28:50 +02:00
28f1eee391 ♻️ (pagetop): Separa handle_component() en 2 métodos
`Theme::handle_component()` se divide en `setup_component()` (síncrono,
muta por tipo con la macro homónima) y `render_component()` (async,
decide el renderizado con su propia macro). Aplica mismo criterio que ya
separa `Component::setup()` de `prepare()`.
2026-09-06 13:07:01 +02:00
1e2d171805 ♻️ (pagetop): setup() recibe &mut Context
Antes sólo mutaba el propio componente; ahora también puede aplicar
ajustes síncronos sobre el Context, visibles para las extensiones que
intercepten BeforeRender. La frontera con prepare() pasa a ser de
sincronía, no de qué puede mutar cada uno.
2026-09-06 09:04:44 +02:00
b163b7726e ♻️ (util): Simplifica normalize_ascii*
`normalize_ascii_or_empty()` pasa a llamarse `normalize_ascii()` (la
variante indulgente, la más usada); la antigua `normalize_ascii()` pasa
a `normalize_ascii_non_blank()`.
2026-09-05 21:19:15 +02:00
ab1d4f0efb ♻️ (pagetop): Incorpora Context al render de Props 2026-09-05 00:19:39 +02:00
17e16652e4 ✨ (pagetop): Añade Flex/FlexItem para usar Flexbox
Container y Navbar lo adoptan vía `with_flex()`/`PropsOp::flex_item()`.
Y se elimina `ButtonSet` porque su funcionalidad queda cubierta por este
mecanismo más general. Incluye el ejemplo `examples/intro-flex.rs` con
los patrones de uso.
2026-09-04 01:04:53 +02:00
4e4fdf7b10 📝 Resalta términos en docs de Block y Breadcrumb 2026-08-29 19:52:45 +02:00
1be3d88888 ♻️ Migra #[builder_fn] a #[builder_impl]
Sustituye las ~400 anotaciones `#[builder_fn]` método a método por un
único `#[builder_impl]` por `impl`/`trait`, en 74 ficheros de pagetop y
sus extensiones (admin, bootsier, menu, user).
2026-08-29 19:25:58 +02:00
35ae5bb6a8 ✨ (base): Añade componentes Nav y Navbar
Dropdown incorpora tamaño y estilo de botón configurables
(`button::Size`/`Style`), reutilizados también por Navbar. El tema Basic
sirve `basic.min.css` y añade el JS de inicialización de Navbar.
2026-08-28 18:24:43 +02:00
da959183f6 ✨ (button): Añade Button::anchor() para navegación
- Renderiza un `<a href>` real con el aspecto de un botón, distinto del
  estilo puramente visual `button::Style::Link`.
- Renombra `ButtonKind`/`ButtonStyle` a `Kind`/`Style`.
- Añade `button::Size` (`button-sm`/`button-lg`).
2026-08-28 11:38:57 +02:00
56a6691c87 🚧 (theme): Renombra variantes de Intent
Renombra `Intent::Secondary`/`Danger` a `Neutral`/`Severe` y actualiza
Badge y su CSS por defecto (basic.css) al nuevo vocabulario.

Introduce el punto de extensión `Theme::intent_color()`, que traduce una
`Intent` al nombre de color de la paleta propia de cada tema, con
`Intent::color(cx)` como atajo de uso desde los componentes.
2026-08-28 01:10:45 +02:00
af53cd4b52 ♻️ (dropdown): Integra Dropdown con accessible-menu
Renombra `dropdown.init.js` a `basic.dropdown.init.js` y añade cierre
cruzado entre menús abiertos y cierre al clicar fuera. Corrige el icono
de apertura/cierre y el estado cerrado por defecto de dropdown-menu.
Migra `with_item` de `ChildOp` a `TypedOp<dropdown::Item>`.
2026-08-26 23:58:33 +02:00
76c5cb9b76 ✨ (base): Añade componente Dialog
Sustituye `PropsOp::Translate` por `Rename` para que los temas traduzcan
atributos `data-dialog-*` al vocabulario propio (p. ej. `data-bs-*` en
Bootsier).
2026-08-26 21:56:10 +02:00
99a4837e11 ✨ (button): Añade componentes Button y ButtonSet 2026-08-24 20:18:29 +02:00
e24b9ab9de ♻️ (pagetop): Logotipo embebido y Badge en Intent
- `PageTopSvg::markup_with()` fusiona `Props` y controla la etiqueta
  accesible directamente en el `<svg>`.
- `Image` ya no duplica accesibilidad para el logotipo y corrige el
  `alt` vacío en el resto de fuentes (Responsive/Thumbnail/Plain).
- Sustituye `BadgeKind` y el `ColorName`/`IntoColor` de `core/theme`
  por un `Intent` compartido.
2026-08-22 09:44:28 +02:00
4ba66f5995 🚧 (base): Añade BadgeKind para el tipo de Badge 2026-08-21 11:18:16 +02:00
fe2b2c176f ♻️ (bootsier): Mueve Brand al core de PageTop 2026-08-17 05:53:55 +02:00
bf4c635e59 ♻️ (pagetop): Sustituye Attr<T> por Option<T>
`Attr<T>` no aportaba nada sobre `Option<T>` directo: `Getters` ya trata
los campos `Option<T>` como caso especial (`Option<&T>`, o `Option<T>`
con `#[getters(copy)]`) y `#[builder_fn]` funciona igual sobre ellos.
2026-08-17 05:28:12 +02:00
213aa18b12 ♻️ (locale): Sustituye Attr<Lc> por Lc::none() 2026-08-17 03:16:49 +02:00
c3ff8a6ff8 ♻️ (bootsier): Mueve Image al core de PageTop
`Image`, `Size` y `Source` pasan a `pagetop::base::component` como
componente genérico reutilizable por cualquier tema. Bootsier
sustituye las clases semánticas por las de Bootstrap (`img-fluid`,
`img-thumbnail`) interceptando `setup()`.
2026-08-17 00:55:35 +02:00
946d335664 ✨ (base): Añade componente Dropdown 2026-08-14 20:01:15 +02:00
e5431bc7d7 ✨ (base): Añade componente Messages
Muestra los mensajes acumulados en el Context por severidad.
2026-08-13 17:35:23 +02:00
3930499664 🐛 (table): Añade conversión From<C> a Cell 2026-08-13 15:29:54 +02:00
5842ea6efc ✨ (base): Añade componente Table
Incluye columnas ordenables (`table::SortLink`), paso de props/atributos
a filas y celdas para HTMX, y un mensaje de "sin datos" traducible con
valor por defecto.
2026-08-13 15:17:23 +02:00
17a9f0c9e0 ♻️ (form): Añade #[builder_fn] a Item y Group
Uniforma el criterio con el resto de elementos de componente (`Row`/
`Cell`/`Column`/`SortLink` en table, `Crumb` en breadcrumb) generando su
`alter_...` equivalente para poder mutarse con `&mut self`.
2026-08-13 11:01:32 +02:00
aa8c4100b0 ✨ (base): Añade conversión de Lc a Child/ChildOp 2026-08-12 23:57:31 +02:00
be10dd28a1 ♻️ (locale): Renombra L10n a Lc
Simplifica el nombre del tipo de localización. Actualiza todas las
referencias en el crate principal, extensiones, ejemplos y tests.
2026-08-12 22:56:09 +02:00
3198b74399 🐛 (locale): Corrige escapado de L10n::using()
`L10n::using()` insertaba el texto de `L10n::n()` sin escapar,
tratándolo igual que una traducción de confianza (`l()`/`t()`); ahora se
escapa como cualquier otro valor interpolado con `html!`.

Además, `using()` no debe usarse en valores de atributo. Su marcado de
confianza para `l()`/`t()` podría romper el delimitador si la traducción
contuviera una comilla. Se sustituye por `lookup()`
2026-08-12 14:28:47 +02:00
6bea4a5793 ✨ (base): Añade componente Breadcrumb 2026-08-11 00:46:45 +02:00
20b6c77c9e 🐛 (base): Exporta PagerAlign y corrige aria-label 2026-08-10 13:19:59 +02:00
825283caa3 ♻️ (base): El resumen de Pager usa PagerVisibility
Sustituye el bool de `summary` por `PagerVisibility`, con `Auto` como
valor por defecto: se activa igual que los botones de navegación y el
formulario de salto, sólo cuando el listado se trunca.
2026-08-07 23:47:14 +02:00
ee57d6cacf ✨ (base): Añade resumen de páginas en Pager 2026-08-07 19:03:59 +02:00