Pular para o conteúdo principal

Componentes

O Nerdify fornece um sistema de componentes para construir interfaces dinâmicas. Os componentes são definidos no backend (Ruby) e renderizados automaticamente no frontend (Angular).


Tipos de Componentes​

O Nerdify suporta os seguintes tipos de componentes:

TipoDescrição
containerContainer genérico para agrupar outros componentes
fieldsetVisual de fieldset (diferente de fieldset real)
buttonBotão de ação
textTexto estático ou dinâmico
iconÍcone Material Design
imageImagem
inputCampo de entrada (viewonly ou editável)
cardCard com estrutura visual
embedIncorpora outro recurso/página
listLista de itens
nameExibe o nome do recurso

Container​

O container é o componente mais versátil, usado para agrupar e organizar outros componentes.

component :container, size: 12, styles: { padding: { left: 2, right: 2 } } do
component :text, name: :title, type: :h4
component :text, name: :description
end

Opções do Container​

OpçãoTipoDescrição
sizeIntegerLargura em colunas (1-12)
stylesHashEstilos CSS personalizados
render_ifStringCondição para renderizar (JavaScript)
clickHashAção ao clicar
positionSymbolPosição (:right, :left)

Exemplo com Layout Complexo​

component :container, name: "header", size: 12 do
component :container, size: 6 do
component :text, name: :name, type: :h3
end

component :container, size: 6, position: :right do
component :text, name: :total, styles: { color: "primary" }
end
end

Text​

Exibe texto estático (label) ou dinâmico (valor do campo).

# Texto dinâmico (valor do campo)
component :text, name: :customer_name

# Texto estático (label traduzido)
component :text, name: :title, static: true

# Com tipo de heading
component :text, name: :name, type: :h4

Opções do Text​

OpçãoTipoDescrição
nameSymbolNome do campo ou chave de tradução
typeSymbolTipo: :h1 a :h6, :small, :span, :p
staticBooleanSe true, exibe o label traduzido
stylesHashEstilos personalizados
tooltipBoolean/SymbolExibe tooltip com informação adicional

Estilos Comuns​

component :text, name: :value, styles: {
color: "primary", # primary, danger, success, warning, info
font_weight: 5, # 1-9
font_size: 6, # 1-9
nowrap: true, # Não quebra linha
align: { body: "center" } # Alinhamento
}

Icon​

Exibe ícones do Material Design.

component :icon, name: :shopping_cart

# Com estilos
component :icon, name: :star, styles: {
color: "warning",
font_size: 4
}

# Ícone outlined
component :icon, name: :info, icon_type: :outlined

Opções do Icon​

OpçãoTipoDescrição
nameSymbolNome do ícone Material
icon_typeSymbol:filled (padrão) ou :outlined
staticBooleanSe true, ícone fixo sem valor do campo
stylesHashEstilos personalizados
tooltipSymbolTooltip com tradução do campo
clickHashAção ao clicar

Image​

Exibe uma imagem.

component :image, name: :photo_url

# Com tamanho personalizado
component :image, name: :avatar, image_size: 4, styles: {
rounded: { top_left: 5, top_right: 5, bottom_left: 5, bottom_right: 5 }
}

Opções da Image​

OpçãoTipoDescrição
nameSymbolCampo que contém a URL da imagem
image_sizeIntegerTamanho da imagem (1-12)
stylesHashEstilos (rounded, padding, etc)

Input​

Exibe um campo de input, geralmente em modo viewonly.

# Campo viewonly
component :input, input_type: :money, name: :total, view: :viewonly, label: false

# Campo select viewonly
component :input, input_type: :select, name: :status, view: :viewonly, layout: :inline

Opções do Input​

OpçãoTipoDescrição
nameSymbolNome do campo
input_typeSymbolTipo: :text, :money, :select, etc
viewSymbol:viewonly para apenas visualização
labelBooleanExibe ou oculta o label
layoutSymbol:inline para layout horizontal
sizeInteger/NilLargura em colunas

Embed​

Incorpora outro recurso ou página dentro do componente atual.

component :embed, name: :pets, path: "/customers/:resource.id/pets", size: 12

# Com detecção de mudanças
component :embed, name: :activities, path: "/activities/:resource.id", detect_changes: true

Opções do Embed​

OpçãoTipoDescrição
nameSymbolIdentificador do embed
pathStringCaminho do recurso (suporta interpolação)
sizeIntegerLargura em colunas
detect_changesBooleanRecarrega quando há mudanças

Interpolação de Path​

Use :resource.campo para interpolar valores:

path: "/customers/:resource.id/pets"
path: "/sales/:resource.sale_id/items"

Button​

Cria um botão de ação.

component :button, name: :save, click: { submit: "form" }

# Com estilos
component :button, name: :cancel, click: { close: :dialog }, styles: {
background: "transparent",
color: "danger"
}

Opções do Button​

OpçãoTipoDescrição
nameSymbolNome/label do botão
clickHashAção ao clicar
stylesHashEstilos personalizados
iconSymbolÍcone do botão

Card​

Cria um card com estrutura visual.

component :card, name: :info_card do
component :text, name: :title, type: :h5
component :text, name: :description
end

Estilos Comuns​

Cores​

styles: { color: "primary" }   # Cor do texto
styles: { background: "light" } # Cor de fundo

Valores: primary, secondary, success, danger, warning, info, light, dark, white, transparent

Espaçamento​

styles: {
padding: { left: 2, right: 2, top: 1, bottom: 1 },
margin: { left: 1, right: 1 }
}

Valores: 0-5 (unidades de espaçamento Bootstrap)

Bordas​

styles: {
border: { top: 1, right: 1, bottom: 1, left: 1 },
rounded: { top_left: 2, top_right: 2, bottom_left: 2, bottom_right: 2 }
}

Alinhamento​

styles: {
align: { body: "center" }, # center, left, right
vertical_align: { top: "start" }, # start, center, end
orientation: { body: "vertical" } # vertical, horizontal
}

Outros​

styles: {
font_weight: 5, # 1-9
font_size: 6, # 1-9
opacity: 50, # 0-100
nowrap: true, # Não quebra linha
height: 100 # Altura em porcentagem
}

Renderização Condicional​

Use render_if para exibir componentes condicionalmente:

# Condição baseada no recurso
component :text, name: :discount, render_if: "resource.has_discount"

# Condição com comparação
component :icon, name: :star, render_if: "resource.stars.length > 0"

# Negação
component :text, name: :empty, render_if: "!resource.items || resource.items.length == 0"

A expressão é avaliada no frontend (JavaScript).


Ações de Click​

click: { redirect_to: "/customers/:resource.id" }
click: { redirect_to: ":resource.phone_link", target: "_blank" }

Abrir Dialog​

click: { redirect_to: "edit", open_in: :dialog }

Fechar Dialog​

click: { close: :dialog }

Submit de Formulário​

click: { submit: "form_name" }

Requisição HTTP​

click: {
put: ":resource.id/approve",
success: { toast: :success, update: "resource" },
error: { toast: :error }
}

Exemplo Completo​

fieldset :customer_show, size: 12 do
component :container, size: 3, styles: { border: { right: 1 } } do
component :container, styles: { align: { body: "center" }, padding: { top: 3 } } do
component :image, name: :photo_url, image_size: 4, styles: {
rounded: { top_left: 5, top_right: 5, bottom_left: 5, bottom_right: 5 }
}
component :text, type: :h4, name: :name

component :container do
component :icon, name: :star, static: true, styles: { color: "warning" },
render_if: "resource.stars.length > 0"
component :icon, name: :star, static: true, styles: { color: "info", opacity: 50 },
render_if: "resource.stars.length == 0"
end

component :container do
component :icon, name: :phone, static: true, styles: { background: "light" },
render_if: "resource.phone && resource.phone.length > 0",
click: { redirect_to: ":resource.phone_link", target: "_blank" },
tooltip: :phone
end
end

component :container, size: 12, styles: { border: { top: 1 } } do
component :text, type: :small, name: :total_sales, static: true, styles: { font_weight: 5 }
component :input, input_type: :money, name: :ltv, view: :viewonly, label: false,
styles: { color: "primary" }
end
end

fieldset :customer_tabs, size: 9 do
fieldset :about, tab: :about, size: 12 do
field :name, presence: true
field :email
field :phone
end

fieldset :sales, tab: :sales, size: 12 do
component :embed, name: :sales, path: "/customers/:resource.id/sales", size: 12
end
end
end

Boas Práticas​

Faça​

  • Use container para agrupar componentes relacionados
  • Aproveite render_if para interfaces dinâmicas
  • Use styles consistentes em toda a aplicação
  • Documente componentes complexos

Evite​

  • Aninhar muitos níveis de containers
  • Duplicar estilos - extraia para constantes
  • Misturar lógica de negócio nos componentes
  • Criar componentes muito genéricos