gbr/ui/theme/lustre
GBR: UI Theme Lustre Module
Descrição
Módulo que sobre-escreve funções do módulo lustre/element/html utilizando o
tipo ui.UITheme como argumento. Utiliza o tipo UILustre os tokens (ADT)
que representam as funções lustre. Exemplo:
Sem ui.UITheme:
import lustre/element/html as h
pub fn main() {
let theme = [
// codigos p/ selecionar tema primário ou defaul (fallback)
...
]
h.span(theme, [h.text("Olá mundo!")])
}
Com ui.Theme:
import gbr/ui/lustre as h
pub fn main() {
ui.new()
|> ui.with_variant(ui.primary())
|> ui.with_appearance(ui.ghost())
|> ui.with_design_to_tokens(fn(v, a, _) {
case v, a {
ui.VariantPrimary, _ -> [
h.Style("display", "block"),
h.Class("text-primary-700"),
h.Classes([#("hover:text-primary-800", a == ui.AppearanceGhost)]),
]
_, _ -> "text-gray-800"
}
})
|> h.span([],[h.text("Olá mundo!")])
}
Implementaçâo Do Tema Usando o Lustre
Lustre + UIThemeBuilder
Utilizamos os design tokens do tema como uma estrutura de uma tupla
#(String, Bool), compatível com a assinatura da função attribute.classes
do lustre.
pub fn to_lustre(
theme: UITheme(UILustre),
attributes: List(a.Attribute(a)),
elements: List(element.Element(a)),
to_lustre: fn(List(a.Attribute(a)), List(element.Element(a))) ->
element.Element(a),
) -> element.Element(a) {
let engine_lustre = fn(token) {
case token {
Class(token) -> a.class(token)
Classes(token) -> a.classes(token)
Styles(token) -> a.styles(token)
Style(key, value) -> a.style(key, value)
Empty -> a.none()
}
}
ui.view(theme, fn(tokens: List(UILustre)) {
let attributes =
list.map(tokens, engine_lustre)
|> list.append(attributes)
to_lustre(attributes, elements)
})
}
A função acima é o coração deste módulo, ela converte a lista de tokens,
representando os design tokens lustre gerados pelo tema, em um atributo
lustre attribute.Attribute(msg), usando attribute.classes, a.class,
a.styles, etc.
Abaixo segue como o tema utiliza a injeção desta implementação
import lustre/attribute as a
import lustre/element/html as h
pub fn new_theme_admin() {
theme.new()
|> theme.with_size_to_tokens(size_classes)
|> theme.with_shape_to_tokens(rounded_classes)
|> theme.with_elevation_to_tokens(border_classes)
|> theme.with_stacking_to_tokens(stack_classes)
|> theme.with_design_to_tokens(design_classes)
}
pub fn size_classes(size) {
case size {
ui.SizeMd -> "h-120 w-240"
ui.SizeSm -> "h-90 w-120"
// ...
}
}
// ...
pub fn alert(text) {
// Estilos externos
let attributes = [ a.class("mb-2") ]
// O texto do alerta (inner)
let elements = [h.text(text)]
let to_alert = fn(theme) {
// Motor de design tokens para um elemento lustre
to_lustre(theme, attributes, elements, h.div)
|> theme.view(theme, _)
}
new_theme_admin()
|> theme.with_variant(theme.VariantPrimary)
|> theme.with_appearance(theme.AppearanceFill)
|> theme.with_state(theme.StateFocus)
|> theme.with_size(theme.SizeLg)
|> theme.with_shape(theme.ShapePill)
|> theme.with_elevation(theme.ElevationFlat)
|> theme.with_stacking(theme.StackXxl)
|> to_alert
}
Regra da Propriedade do CSS
- Componente é dono de si mesmo: Ele dita o seu próprio padding,
background, text-color e border-radius. Se o usuário quer um botão menor,
ele deve usar a ADT
theme.SizeSm. - Usuário é dono do espaço exterior (DOM): O argumento
attributesserve EXCLUSIVAMENTE para injetar:- Margens: mt-4, mb-2 (porque o botão não sabe se ele está perto ou longe de outro elemento).
- Posicionamento: absolute, flex.
- Metadados do DOM: id=“meu-botao”, aria-label, data-testid.
- Eventos extras: on_mouse_enter, on_blur.
Types
Tipos que representam os design tokens convertidos para atributos lustre.
- Classes: Convertido para a.classes
- Styles: Convertido para a.styles
- Style: Convertido para a.style
- Class: Convertido para a.class
pub type UILustre {
Classes(List(#(String, Bool)))
Styles(List(#(String, String)))
Style(String, String)
Class(String)
Attribute(String, String)
Empty
}
Constructors
-
Classes(List(#(String, Bool))) -
Styles(List(#(String, String))) -
Style(String, String) -
Class(String) -
Attribute(String, String) -
Empty
Values
pub fn a(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn article(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define um conteúdo independente, auto-contindo.
pub fn aside(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define um conteúdo a parte do conteúdo principal.
pub fn button(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn details(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define detalhes adicionais que pode ser aberto para visualização.
- Usado em conjunto com o
summary(). Algumas interfaces oferecem uma descrição de resumo,summary, padrão.
pub fn div(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn footer(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define um rodapé para o documento ou seção.
pub fn h1(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn h2(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn h3(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn h4(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn h5(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn h6(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn header(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define um cabeçalho para o documento ou seção.
pub fn img(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
) -> element.Element(a)
pub fn input(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
) -> element.Element(a)
pub fn label(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn li(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn main(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn nav(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define um conjunto de links de navegação.
pub fn option(
theme: theme.UITheme(UILustre),
label: String,
attributes: List(attribute.Attribute(a)),
) -> element.Element(a)
<select…><option …/>
pub fn p(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn pre(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn section(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define uma seção no documento.
pub fn select(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn span(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn summary(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
Define o cabeçalho para o elemento details(), caso necessário.
pub fn svg(
theme: theme.UITheme(UILustre),
with attributes: List(attribute.Attribute(a)),
inner elements: List(element.Element(a)),
) -> element.Element(a)
pub fn table(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn td(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn text(text: String) -> element.Element(a)
pub fn textarea(
theme: theme.UITheme(UILustre),
text: String,
a: List(attribute.Attribute(a)),
) -> element.Element(a)
pub fn th(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn to_lustre(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
to_lustre: fn(
List(attribute.Attribute(a)),
List(element.Element(a)),
) -> element.Element(a),
) -> element.Element(a)
Conversor dos design tokens para um elementos lustre.
- theme: Design tokens gerados a partir do tema + o construtor de temas.
- attributes: Atributos do elemento lustre.
- elements: Elementos internos, caso necessário.
- to_lustre: Construtor do elemento lustre.
pub fn tr(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)
pub fn ul(
theme: theme.UITheme(UILustre),
attributes: List(attribute.Attribute(a)),
elements: List(element.Element(a)),
) -> element.Element(a)