Commit 155f50e9 authored by Eduardo Silva's avatar Eduardo Silva
Browse files

ajustes nas tags e templates do dsgov

parent 98f84dfe
...@@ -5,24 +5,30 @@ ...@@ -5,24 +5,30 @@
{% block content %} {% block content %}
<nav class="br-breadcrumb" aria-label="Breadcrumbs"> <nav class="br-breadcrumb" aria-label="Breadcrumbs">
<ol class="crumb-list" role="list"> <ol class="crumb-list" role="list">
{% if items %}
<!-- Primeiro item (Home) - Apenas ícone -->
{% with items.0 as home %}
<li class="crumb home"> <li class="crumb home">
<a class="br-button circle" href="javascript:void(0)"> <a class="br-button circle" href="{{ home.0 }}">
<span class="sr-only">Página inicial</span> <span class="sr-only">{{ home.1 }}</span>
<i class="fas fa-home"></i> <i class="fas fa-home"></i>
</a> </a>
</li> </li>
<li class="crumb"><i class="icon fas fa-chevron-right"></i> {% endwith %}
<a href="javascript:void(0)">Página Ancestral 01</a> <!-- Demais ancestrais (começando do segundo item) -->
{% for url, title in items|slice:"1:" %}
<li class="crumb">
<i class="icon fas fa-chevron-right"></i>
<a href="{{ url }}">{{ title }}</a>
</li> </li>
<li class="crumb"><i class="icon fas fa-chevron-right"></i> {% endfor %}
<a href="javascript:void(0)">Página Ancestral 02</a> {% endif %}
</li> <!-- Página atual -->
<li class="crumb"><i class="icon fas fa-chevron-right"></i> <li class="crumb" data-active="active">
<a href="javascript:void(0)">Página Ancestral 03</a> <i class="icon fas fa-chevron-right"></i>
</li> <span tabindex="0" aria-current="page">{{ current_title }}</span>
<li class="crumb" data-active="active"><i class="icon fas fa-chevron-right"></i>
<span tabindex="0" aria-current="page">Página atual</span>
</li> </li>
</ol> </ol>
</nav> </nav>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -6,12 +6,16 @@ ...@@ -6,12 +6,16 @@
<div class="br-card hover" style="cursor: pointer;"> <div class="br-card hover" style="cursor: pointer;">
<div class="card-content"> <div class="card-content">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
{% if icon_svg %} {% if icon_class %}
<img src="{% static icon_svg %}" alt="ícone" width="40" height="40" class="mr-3"/> <i class="fas {{ icon_class }} {{ icon_extra_class }}" style="{{ icon_style }}"></i>
{% endif %} {% endif %}
<div> <div>
<h4 class="mt-0 mb-1 text-primary" style="font-family: 'Noto Sans', sans-serif;">{{ title }}</h4> <h4 class="{{ title_class }}" style="{{ title_style }}">
<p style="font-family: 'Noto Sans', sans-serif; color: #5C5C5C;">{{ text }}</p> {{ title }}
</h4>
<p class="{{ text_class }}" style="{{ text_style }}">
{{ text }}
</p>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -2,11 +2,17 @@ from django import template ...@@ -2,11 +2,17 @@ from django import template
from django.utils.html import format_html from django.utils.html import format_html
from django.templatetags.static import static from django.templatetags.static import static
from django.template.loader import render_to_string from django.template.loader import render_to_string
from urllib.parse import urlencode, parse_qs
register = template.Library() register = template.Library()
@register.simple_tag @register.simple_tag
def br_stylesheets(): def br_stylesheets():
"""
Renderiza as folhas de estilo principais do DSGov.
Inclui o CSS do DSGov e a fonte Rawline.
Os caminhos são resolvidos via staticfiles do Django.
"""
return format_html( return format_html(
""" """
<link rel="stylesheet" href="{}"> <link rel="stylesheet" href="{}">
...@@ -18,6 +24,10 @@ def br_stylesheets(): ...@@ -18,6 +24,10 @@ def br_stylesheets():
@register.simple_tag @register.simple_tag
def br_scripts(): def br_scripts():
"""
Renderiza o script principal do DSGov.
Inclui o bundle JS como módulo, necessário para componentes interativos.
"""
return format_html( return format_html(
""" """
<script type="module" src="{}"></script> <script type="module" src="{}"></script>
...@@ -25,130 +35,209 @@ def br_scripts(): ...@@ -25,130 +35,209 @@ def br_scripts():
static('dsgov/dist/js/bundle.js') static('dsgov/dist/js/bundle.js')
) )
@register.simple_tag @register.simple_tag
def br_button(text='', button_type='', style='', extra_classes='', icon_class=''): def br_button(text='', button_type='', style='', extra_classes='', icon_class=''):
"""
Renderiza um botão DSGov customizado.
Permite definir texto, tipo, estilo (primary/secondary), classes extras e ícone.
Os valores default garantem aparência consistente, mas podem ser sobrescritos no template.
"""
style_class = f'{style}' if style in ['primary', 'secondary'] else '' style_class = f'{style}' if style in ['primary', 'secondary'] else ''
classes = f'br-button {style_class} {extra_classes}'.strip() classes = f'br-button {style_class} {extra_classes}'.strip()
icon_html = format_html('<i class="{}" aria-hidden="true"></i>', icon_class) if icon_class else '' icon_html = format_html('<i class="{}" aria-hidden="true"></i>', icon_class) if icon_class else ''
return format_html('<button type="{}" class="{}">{}{}</button>', button_type, classes, icon_html, text) return format_html('<button type="{}" class="{}">{}{}</button>', button_type, classes, icon_html, text)
@register.simple_tag @register.simple_tag
def br_tag(tag_text="", tag_id="", icon_class="", close_button="", close_icon_class="", button_extra_classes="", extra_classes="", density=""): def br_tag(tag_text="", tag_id="", icon_class="", close_button="", close_icon_class="", button_extra_classes="", extra_classes="", density=""):
"""
Renderiza um componente de tag DSGov.
Permite adicionar ícone, botão de fechar, classes extras e densidade.
Os valores default garantem visual padrão, mas podem ser editados no template.
"""
icon_html = format_html('<i class="{}" aria-hidden="true"></i>', icon_class) if icon_class else "" icon_html = format_html('<i class="{}" aria-hidden="true"></i>', icon_class) if icon_class else ""
close_button_html = "" close_button_html = ""
if close_button: if close_button:
close_button_html = format_html( '<button class="br-button inverted circle {}" type="button" aria-label="Fechar" aria-describedby="{}" data-dismiss="{}">' '<i class="{}" aria-hidden="true"></i></button>', button_extra_classes, tag_id, tag_id, close_icon_class) close_button_html = format_html(
'<button class="br-button inverted circle {}" type="button" aria-label="Fechar" aria-describedby="{}" data-dismiss="{}">'
'<i class="{}" aria-hidden="true"></i></button>',
button_extra_classes, tag_id, tag_id, close_icon_class
)
interaction_class = "interaction" if close_button else "" interaction_class = "interaction" if close_button else ""
tag_html = format_html(
tag_html = format_html('<span class="br-tag {} {} {}" id="{}" aria-describedby="{}">' '{}<span>{}</span>{}</span>', extra_classes, density, interaction_class, tag_id, tag_id, icon_html, tag_text, close_button_html) '<span class="br-tag {} {} {}" id="{}" aria-describedby="{}">'
'{}<span>{}</span>{}</span>',
extra_classes, density, interaction_class, tag_id, tag_id, icon_html, tag_text, close_button_html
)
return format_html('<div class="d-flex align-items-center flex-wrap gap-2">{}</div>', tag_html) return format_html('<div class="d-flex align-items-center flex-wrap gap-2">{}</div>', tag_html)
@register.simple_tag @register.simple_tag
def br_input(input_type="", placeholder="", label="", input_id="", help_text="" ,extra_classes="", density="" , icon_class="", disabled=False, readonly=False, value=""): def br_input(input_type="", placeholder="", label="", input_id="", help_text="" ,extra_classes="", density="" , icon_class="", disabled=False, readonly=False, value=""):
"""
Renderiza um campo de input DSGov.
Permite definir tipo, placeholder, label, ajuda, ícone, estado (disabled/readonly) e classes extras.
Os valores default garantem visual e acessibilidade, mas podem ser sobrescritos no template.
"""
density_class = density if density in ['small', 'large'] else 'medium' density_class = density if density in ['small', 'large'] else 'medium'
classes = f'br-input {density_class} {extra_classes}'.strip() classes = f'br-input {density_class} {extra_classes}'.strip()
disabled_attr = 'disabled' if disabled else '' disabled_attr = 'disabled' if disabled else ''
readonly_attr = 'readonly' if readonly else '' readonly_attr = 'readonly' if readonly else ''
label_html = format_html('<label for="{}">{}</label>', input_id, label) if label else '' label_html = format_html('<label for="{}">{}</label>', input_id, label) if label else ''
help_text_html = format_html('<p>{}</p>', help_text) if help_text else '' help_text_html = format_html('<p>{}</p>', help_text) if help_text else ''
if icon_class: if icon_class:
input_html = format_html('<div class="input-group">' '<div class="input-icon"><i class="{}" aria-hidden="true"></i></div>' '<input type="{}" id="{}" placeholder="{}" value="{}" class="{}" {} {}/>' '</div>', icon_class, input_type, input_id, placeholder, value, extra_classes, disabled_attr, readonly_attr) input_html = format_html(
'<div class="input-group">'
'<div class="input-icon"><i class="{}" aria-hidden="true"></i></div>'
'<input type="{}" id="{}" placeholder="{}" value="{}" class="{}" {} {}/>'
'</div>',
icon_class, input_type, input_id, placeholder, value, extra_classes, disabled_attr, readonly_attr
)
else: else:
input_html = format_html('<input type="{}" id="{}" placeholder="{}" value="{}" class="{}" {} {}/>', input_type, input_id, placeholder, value, extra_classes, disabled_attr, readonly_attr) input_html = format_html(
'<input type="{}" id="{}" placeholder="{}" value="{}" class="{}" {} {}/>',
return format_html('<div class="{}">{label_html}{input_html}{help_text_html}</div>', classes, label_html=label_html, input_html=input_html, help_text_html=help_text_html) input_type, input_id, placeholder, value, extra_classes, disabled_attr, readonly_attr
)
return format_html(
@register.simple_tag '<div class="{}">{label_html}{input_html}{help_text_html}</div>',
def br_header(title="", subtitle="", title_extra="", logo_url="", links="", search_placeholder="", show_login=True, extra_classes="", links_style="", label_button_login="", title_style="", items_style="", header_sign_style=""): classes, label_html=label_html, input_html=input_html, help_text_html=help_text_html
)
context = {
'title': title,
'subtitle': subtitle,
'title_extra' : title_extra,
'logo_url': logo_url,
'links': links,
'search_placeholder': search_placeholder,
'show_login': show_login,
'extra_classes': extra_classes,
'links_style': links_style,
'label_button_login': label_button_login,
'title_style': title_style,
'items_style': items_style,
'header_sign_style': header_sign_style
}
return render_to_string('dsgov/components/header.html', context)
@register.simple_tag @register.simple_tag
def br_list(title, items): def br_list(title, items):
"""
Renderiza uma lista DSGov a partir de um template.
Recebe título e itens, permitindo personalização no template.
"""
context = { context = {
"title": title, "title": title,
"items": items, "items": items,
} }
return render_to_string("dsgov/components/list.html", context) return render_to_string("dsgov/components/list.html", context)
@register.simple_tag @register.inclusion_tag("dsgov/components/breadcrumb.html")
def br_carousel(slides=None, responsivo=True): def br_breadcrumb(items=None, current_title=""):
"""
context = { Renderiza o componente de breadcrumb DSGov a partir de um template.
'slides': slides or [], Uso no template:
'responsivo': responsivo {% br_breadcrumb items=breadcrumb_list current_title=page.title %}
} """
return render_to_string('dsgov/components/carousel.html', context)
@register.simple_tag
def br_menu(icon_style="", text_color=""):
context = {
"icon_style": icon_style,
"text_color": text_color
}
return render_to_string('dsgov/components/menu.html', context)
@register.inclusion_tag('dsgov/components/breadcrumb.html')
def br_breadcrumb(pages=""):
return { return {
'pages': pages, "items": items or [],
"current_title": current_title,
} }
@register.simple_tag @register.simple_tag
def br_pagination(pages=""): def br_pagination(total_pages=1, current_page=1, base_url="?page=", extra_params=""):
"""
context = { Renderiza um componente de paginação DSGov preservando parâmetros GET.
'pages': pages, Uso no template:
} {% br_pagination total_pages=noticias.paginator.num_pages current_page=noticias.number base_url="?page=" extra_params=request.GET.urlencode %}
Os valores default garantem funcionamento básico, mas todos os parâmetros podem ser editados manualmente no template.
"""
# Garantindo limites
total_pages = int(total_pages)
current_page = int(current_page)
# --- Tratamento dos parâmetros extras ---
params = parse_qs(extra_params) if extra_params else {}
params.pop("page", None)
# Reconstroi querystring
querystring = "&" + urlencode(params, doseq=True) if params else ""
# --- Links de navegação ---
prev_disabled = "disabled" if current_page <= 1 else ""
prev_link = (
f'{base_url}{current_page-1}{querystring}'
if current_page > 1 else "javascript:void(0)"
)
next_disabled = "disabled" if current_page >= total_pages else ""
next_link = (
f'{base_url}{current_page+1}{querystring}'
if current_page < total_pages else "javascript:void(0)"
)
# --- Lista de páginas ---
pages_html = ""
for num in range(1, total_pages + 1):
active_class = "active" if num == current_page else ""
pages_html += f"""
<li>
<a class="page {active_class}" href="{base_url}{num}{querystring}" aria-label="página {num}">{num}</a>
</li>
"""
# --- HTML final ---
return format_html(
"""
<nav class="br-pagination" aria-label="paginação" data-total="{total}" data-current="{current}">
<ul>
<li>
<a class="br-button circle {prev_disabled}" href="{prev_link}" aria-label="Voltar página">
<i class="fas fa-angle-left" aria-hidden="true"></i>
</a>
</li>
{pages}
<li>
<a class="br-button circle {next_disabled}" href="{next_link}" aria-label="Página seguinte">
<i class="fas fa-angle-right" aria-hidden="true"></i>
</a>
</li>
</ul>
</nav>
""",
total=total_pages,
current=current_page,
prev_disabled=prev_disabled,
next_disabled=next_disabled,
prev_link=prev_link,
next_link=next_link,
pages=format_html(pages_html),
)
return render_to_string('dsgov/components/pagination.html', context) @register.simple_tag(takes_context=True)
def br_search(context, placeholder="Buscar...", input_id="search-input", btn_label="Buscar", input_name="q"):
"""
Renderiza um campo de busca com botão.
Agora preenche automaticamente com o valor digitado.
Os valores default garantem funcionamento básico, mas podem ser sobrescritos no template.
"""
request = context['request']
value = request.GET.get(input_name, '')
return format_html(
"""
<form method="get" action="" class="mb-5">
<div class="br-input input-highlight w-100">
<label class="sr-only" for="{id}">Label / Rótulo</label>
<input id="{id}" name="{name}" type="search" placeholder="{ph}" value="{val}" class="w-100">
<button class="br-button" type="submit" aria-label="{btn}">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
</form>
""",
id=input_id,
ph=placeholder,
btn=btn_label,
name=input_name,
val=value
)
@register.simple_tag @register.simple_tag
def br_card(title='', text='', icon_path=None): def br_card(title='', text='', icon_class=None, icon_extra_class="", icon_style="", title_class="mt-0 mb-1 text-primary", title_style="font-family: 'Noto Sans', sans-serif;", text_class="text-gray-700", text_style="font-family: 'Noto Sans', sans-serif; color:#5C5C5C;"):
"""
Renderiza um card customizado com ícone, título e texto, seguindo o padrão visual do DSGov.
Os parâmetros permitem personalizar classes e estilos do card diretamente pelo template.
Os valores default dos parâmetros garantem que o card tenha estilos, cores e espaçamentos padronizados,
mesmo que nenhum valor seja passado pelo template. Isso facilita o uso rápido e mantém a identidade visual.
Mesmo com esses valores padrão, é possível sobrescrever qualquer parâmetro manualmente no template,
permitindo total controle sobre o visual do card conforme a necessidade do projeto.
"""
context = { context = {
'title': title, "title": title,
'text': text, "text": text,
'icon_svg': icon_path "icon_class": icon_class,
"icon_extra_class": icon_extra_class,
"icon_style": icon_style,
"title_class": title_class,
"title_style": title_style,
"text_class": text_class,
"text_style": text_style,
} }
return render_to_string('dsgov/components/card_with_icon.html', context) return render_to_string("dsgov/components/card_with_icon.html", context)
from django import template from django import template
from django.utils.safestring import mark_safe
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.template.base import token_kwargs from django.template.base import token_kwargs
register = template.Library() register = template.Library()
@register.tag(name='br_menu_row') @register.tag(name='br_menu_row')
def do_br_menu_row(parser, token): def do_br_menu_row(parser, token):
"""
Renderiza uma linha (row) para agrupar elementos do menu.
Usado para estruturar o layout do menu principal.
"""
nodelist = parser.parse(('end_br_menu_row',)) nodelist = parser.parse(('end_br_menu_row',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuRowNode(nodelist) return BRMenuRowNode(nodelist)
...@@ -21,6 +25,11 @@ class BRMenuRowNode(template.Node): ...@@ -21,6 +25,11 @@ class BRMenuRowNode(template.Node):
@register.tag(name='br_menu') @register.tag(name='br_menu')
def do_br_menu(parser, token): def do_br_menu(parser, token):
"""
Tag de bloco principal para o menu.
Cria a estrutura básica do menu, incluindo o painel de conteúdo e o scrim (camada de fundo).
Abre a tag `br_menu` e fecha com `end_br_menu`.
"""
nodelist = parser.parse(('end_br_menu',)) nodelist = parser.parse(('end_br_menu',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuNode(nodelist) return BRMenuNode(nodelist)
...@@ -44,6 +53,11 @@ class BRMenuNode(template.Node): ...@@ -44,6 +53,11 @@ class BRMenuNode(template.Node):
@register.tag(name='br_menu_header') @register.tag(name='br_menu_header')
def do_br_menu_header(parser, token): def do_br_menu_header(parser, token):
"""
Tag de bloco para o cabeçalho do menu.
Envolve o conteúdo do cabeçalho do menu, como título e logo.
Adiciona um botão de fechar o menu com ícone de 'x'.
"""
nodelist = parser.parse(('end_br_menu_header',)) nodelist = parser.parse(('end_br_menu_header',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuHeaderNode(nodelist) return BRMenuHeaderNode(nodelist)
...@@ -67,6 +81,11 @@ class BRMenuHeaderNode(template.Node): ...@@ -67,6 +81,11 @@ class BRMenuHeaderNode(template.Node):
@register.simple_tag(name='br_menu_header_logo') @register.simple_tag(name='br_menu_header_logo')
def br_menu_header_logo(src): def br_menu_header_logo(src):
"""
Tag simples para exibir o logo no cabeçalho do menu.
Recebe o caminho da imagem (`src`) como argumento.
Retorna uma tag `<img>` com o src e um alt padrão.
"""
return mark_safe(f'<img src="{src}" alt="Imagem ilustrativa"/>') return mark_safe(f'<img src="{src}" alt="Imagem ilustrativa"/>')
class BrMenuTitleNode(template.Node): class BrMenuTitleNode(template.Node):
...@@ -79,6 +98,10 @@ class BrMenuTitleNode(template.Node): ...@@ -79,6 +98,10 @@ class BrMenuTitleNode(template.Node):
@register.tag @register.tag
def br_menu_title(parser, token): def br_menu_title(parser, token):
"""
Tag de bloco para o título do menu.
Envolve o texto do título do menu.
"""
nodelist = parser.parse(['end_br_menu_title']) nodelist = parser.parse(['end_br_menu_title'])
parser.delete_first_token() parser.delete_first_token()
return BrMenuTitleNode(nodelist) return BrMenuTitleNode(nodelist)
...@@ -89,6 +112,11 @@ class BrMenuTitleLogoNode(template.Node): ...@@ -89,6 +112,11 @@ class BrMenuTitleLogoNode(template.Node):
self.alt_expr = alt_expr self.alt_expr = alt_expr
def render(self, context): def render(self, context):
"""
Nó interno para a tag `br_menu_title_logo`.
Renderiza uma tag `<img>` com src e alt dinâmicos.
Resolve os valores de src e alt a partir do contexto do template.
"""
src = "data:image/png;base64,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" src = "data:image/png;base64,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"
alt = "Imagem ilustrativa" alt = "Imagem ilustrativa"
try: try:
...@@ -114,17 +142,29 @@ class BrMenuTitleTextNode(template.Node): ...@@ -114,17 +142,29 @@ class BrMenuTitleTextNode(template.Node):
self.nodelist = nodelist self.nodelist = nodelist
def render(self, context): def render(self, context):
"""
Nó interno para a tag `br_menu_title_text`.
Renderiza o texto do título dentro de uma tag `<span>`.
"""
content = self.nodelist.render(context) content = self.nodelist.render(context)
return format_html('<span>{}</span>', content) return format_html('<span>{}</span>', content)
@register.tag @register.tag
def br_menu_title_text(parser, token): def br_menu_title_text(parser, token):
"""
Tag de bloco para o texto do título do menu.
"""
nodelist = parser.parse(['end_br_menu_title_text']) nodelist = parser.parse(['end_br_menu_title_text'])
parser.delete_first_token() parser.delete_first_token()
return BrMenuTitleTextNode(nodelist) return BrMenuTitleTextNode(nodelist)
@register.tag @register.tag
def br_menu_title_logo(parser, token): def br_menu_title_logo(parser, token):
"""
Tag de bloco para o logo do título do menu.
Recebe os argumentos `src` e `alt` para a imagem.
Compila as expressões de filtro para resolver variáveis no contexto do template.
"""
bits = token.split_contents() bits = token.split_contents()
src_expr = None src_expr = None
alt_expr = None alt_expr = None
...@@ -139,6 +179,11 @@ def br_menu_title_logo(parser, token): ...@@ -139,6 +179,11 @@ def br_menu_title_logo(parser, token):
@register.tag(name='br_menu_body') @register.tag(name='br_menu_body')
def do_br_menu_body(parser, token): def do_br_menu_body(parser, token):
"""
Tag de bloco para o corpo do menu.
Envolve a navegação principal (`nav`).
Adiciona a classe `menu-body` e o atributo `role="tree"`.
"""
nodelist = parser.parse(('end_br_menu_body',)) nodelist = parser.parse(('end_br_menu_body',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuBodyNode(nodelist) return BRMenuBodyNode(nodelist)
...@@ -151,8 +196,13 @@ class BRMenuBodyNode(template.Node): ...@@ -151,8 +196,13 @@ class BRMenuBodyNode(template.Node):
content = self.nodelist.render(context) content = self.nodelist.render(context)
return mark_safe(f'<nav class="menu-body" role="tree">{content}</nav>') return mark_safe(f'<nav class="menu-body" role="tree">{content}</nav>')
@register.tag(name='br_menu_folder') @register.tag(name='br_menu_folder')
def do_br_menu_folder(parser, token): def do_br_menu_folder(parser, token):
"""
Tag de bloco para criar uma pasta/seção no menu.
Gera uma div com a classe `menu-folder`.
"""
nodelist = parser.parse(('end_br_menu_folder',)) nodelist = parser.parse(('end_br_menu_folder',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuFolderNode(nodelist) return BRMenuFolderNode(nodelist)
...@@ -167,6 +217,12 @@ class BRMenuFolderNode(template.Node): ...@@ -167,6 +217,12 @@ class BRMenuFolderNode(template.Node):
@register.tag(name='br_menu_item') @register.tag(name='br_menu_item')
def do_br_menu_item(parser, token): def do_br_menu_item(parser, token):
"""
Tag de bloco para criar um item de menu clicável.
Recebe os argumentos `href` e opcionalmente `icone`.
Gera uma tag `<a>` com as classes `menu-item` e `divider`, e o atributo `role="treeitem"`.
Resolve as variáveis `href` e `icone` do contexto.
"""
bits = token.split_contents() bits = token.split_contents()
tag_name = bits[0] tag_name = bits[0]
...@@ -228,6 +284,11 @@ class BRMenuItemNode(template.Node): ...@@ -228,6 +284,11 @@ class BRMenuItemNode(template.Node):
@register.tag(name='br_menu_divider_item') @register.tag(name='br_menu_divider_item')
def do_br_menu_divider_item(parser, token): def do_br_menu_divider_item(parser, token):
"""
Tag de bloco para um item de menu divisor.
Parecido com `br_menu_item`, mas com comportamento de divisor.
Recebe os argumentos `href` e opcionalmente `icone`.
"""
try: try:
bits = token.split_contents() bits = token.split_contents()
tag_name = bits[0] tag_name = bits[0]
...@@ -267,6 +328,10 @@ class BRMenuDividerItemNode(template.Node): ...@@ -267,6 +328,10 @@ class BRMenuDividerItemNode(template.Node):
@register.tag(name='br_menu_footer') @register.tag(name='br_menu_footer')
def do_br_menu_footer(parser, token): def do_br_menu_footer(parser, token):
"""
Tag de bloco para o rodapé do menu.
Gera uma div com a classe `menu-footer`.
"""
nodelist = parser.parse(('end_br_menu_footer',)) nodelist = parser.parse(('end_br_menu_footer',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuFooterNode(nodelist) return BRMenuFooterNode(nodelist)
...@@ -284,11 +349,19 @@ class BRMenuFooterLogosNode(template.Node): ...@@ -284,11 +349,19 @@ class BRMenuFooterLogosNode(template.Node):
self.nodelist = nodelist self.nodelist = nodelist
def render(self, context): def render(self, context):
"""
Tag de bloco para a seção de logos no rodapé do menu.
Gera uma div com a classe `menu-logos`.
"""
content = self.nodelist.render(context).strip() content = self.nodelist.render(context).strip()
return format_html('<div class="menu-logos">{}</div>', mark_safe(content)) return format_html('<div class="menu-logos">{}</div>', mark_safe(content))
@register.tag(name='br_menu_footer_logos') @register.tag(name='br_menu_footer_logos')
def do_br_menu_footer_logos(parser, token): def do_br_menu_footer_logos(parser, token):
"""
Tag de bloco para a seção de logos no rodapé do menu.
Gera uma div com a classe `menu-logos`.
"""
nodelist = parser.parse(('end_br_menu_footer_logos',)) nodelist = parser.parse(('end_br_menu_footer_logos',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuFooterLogosNode(nodelist) return BRMenuFooterLogosNode(nodelist)
...@@ -299,6 +372,11 @@ class BRMenuLogoNode(template.Node): ...@@ -299,6 +372,11 @@ class BRMenuLogoNode(template.Node):
self.alt_expr = alt_expr or template.FilterExpression('"Imagem ilustrativa"', parser=None) self.alt_expr = alt_expr or template.FilterExpression('"Imagem ilustrativa"', parser=None)
def render(self, context): def render(self, context):
"""
Nó interno para a tag `br_menu_logo`.
Renderiza a tag `<img>` para o logo no rodapé.
Lida com a resolução de variáveis para src e alt, com valores padrão.
"""
try: try:
src = self.src_expr.resolve(context) src = self.src_expr.resolve(context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
...@@ -313,6 +391,10 @@ class BRMenuLogoNode(template.Node): ...@@ -313,6 +391,10 @@ class BRMenuLogoNode(template.Node):
@register.tag(name='br_menu_logo') @register.tag(name='br_menu_logo')
def do_br_menu_logo(parser, token): def do_br_menu_logo(parser, token):
"""
Tag para exibir um logo no rodapé do menu.
Requer o argumento `src` e aceita opcionalmente `alt`.
"""
bits = token.split_contents() bits = token.split_contents()
src_expr = None src_expr = None
alt_expr = None alt_expr = None
...@@ -330,6 +412,10 @@ def do_br_menu_logo(parser, token): ...@@ -330,6 +412,10 @@ def do_br_menu_logo(parser, token):
@register.tag(name="br_menu_links") @register.tag(name="br_menu_links")
def do_br_menu_links(parser, token): def do_br_menu_links(parser, token):
"""
Tag de bloco para a seção de links no rodapé do menu.
Gera uma div com a classe `menu-links`.
"""
nodelist = parser.parse(("end_br_menu_links",)) nodelist = parser.parse(("end_br_menu_links",))
parser.delete_first_token() parser.delete_first_token()
return BRMenuLinksNode(nodelist) return BRMenuLinksNode(nodelist)
...@@ -344,6 +430,10 @@ class BRMenuLinksNode(template.Node): ...@@ -344,6 +430,10 @@ class BRMenuLinksNode(template.Node):
@register.tag(name='br_menu_list') @register.tag(name='br_menu_list')
def do_br_menu_list(parser, token): def do_br_menu_list(parser, token):
"""
Tag de bloco para criar uma lista (`<ul>`) no menu.
Usada para agrupar itens de lista (`<li>`).
"""
nodelist = parser.parse(('end_br_menu_list',)) nodelist = parser.parse(('end_br_menu_list',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuListNode(nodelist) return BRMenuListNode(nodelist)
...@@ -358,6 +448,9 @@ class BRMenuListNode(template.Node): ...@@ -358,6 +448,9 @@ class BRMenuListNode(template.Node):
@register.tag(name='br_menu_list_item') @register.tag(name='br_menu_list_item')
def do_br_menu_list_item(parser, token): def do_br_menu_list_item(parser, token):
"""
Tag de bloco para criar um item de lista (`<li>`) no menu.
"""
nodelist = parser.parse(('end_br_menu_list_item',)) nodelist = parser.parse(('end_br_menu_list_item',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuListItemNode(nodelist) return BRMenuListItemNode(nodelist)
...@@ -372,6 +465,11 @@ class BRMenuListItemNode(template.Node): ...@@ -372,6 +465,11 @@ class BRMenuListItemNode(template.Node):
@register.tag(name="br_menu_link") @register.tag(name="br_menu_link")
def do_br_menu_link(parser, token): def do_br_menu_link(parser, token):
"""
Tag de bloco para um link simples no menu.
Recebe os argumentos opcionais `href` e `icone`.
Gera uma tag `<a>` com o conteúdo e o ícone.
"""
bits = token.split_contents() bits = token.split_contents()
href_expr = None href_expr = None
icon_expr = None icon_expr = None
...@@ -417,6 +515,10 @@ class BRMenuLinkNode(template.Node): ...@@ -417,6 +515,10 @@ class BRMenuLinkNode(template.Node):
@register.tag(name='br_menu_social_network') @register.tag(name='br_menu_social_network')
def do_br_menu_social_network(parser, token): def do_br_menu_social_network(parser, token):
"""
Tag de bloco para a seção de redes sociais no menu.
Gera uma div com a classe `social-network`.
"""
nodelist = parser.parse(('end_br_menu_social_network',)) nodelist = parser.parse(('end_br_menu_social_network',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuSocialNetworkNode(nodelist) return BRMenuSocialNetworkNode(nodelist)
...@@ -435,6 +537,10 @@ class BRMenuSocialNetworkNode(template.Node): ...@@ -435,6 +537,10 @@ class BRMenuSocialNetworkNode(template.Node):
@register.tag(name='br_menu_social_network_title') @register.tag(name='br_menu_social_network_title')
def do_br_menu_social_network_title(parser, token): def do_br_menu_social_network_title(parser, token):
"""
Tag de bloco para o título da seção de redes sociais.
Gera uma div com a classe `social-network-title`.
"""
nodelist = parser.parse(('end_br_menu_social_network_title',)) nodelist = parser.parse(('end_br_menu_social_network_title',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuSocialNetworkTitleNode(nodelist) return BRMenuSocialNetworkTitleNode(nodelist)
...@@ -449,6 +555,11 @@ class BRMenuSocialNetworkTitleNode(template.Node): ...@@ -449,6 +555,11 @@ class BRMenuSocialNetworkTitleNode(template.Node):
@register.simple_tag(name='br_menu_social_network_icons', takes_context=True) @register.simple_tag(name='br_menu_social_network_icons', takes_context=True)
def br_menu_social_network_icons(context, href, icon, extra_classes=""): def br_menu_social_network_icons(context, href, icon, extra_classes=""):
"""
Tag simples para ícones de redes sociais.
Recebe `href`, `icon` (classe do ícone) e `extra_classes` como argumentos.
Renderiza um botão redondo com o link e o ícone.
"""
# Remove aspas se for um valor literal # Remove aspas se for um valor literal
href = href.strip('"\'') href = href.strip('"\'')
...@@ -468,6 +579,10 @@ def br_menu_social_network_icons(context, href, icon, extra_classes=""): ...@@ -468,6 +579,10 @@ def br_menu_social_network_icons(context, href, icon, extra_classes=""):
@register.tag(name='br_menu_copyright') @register.tag(name='br_menu_copyright')
def do_br_menu_copyright(parser, token): def do_br_menu_copyright(parser, token):
"""
Tag de bloco para a seção de copyright no menu.
Gera uma div com a classe `menu-info` e o texto com a classe `text-center text-down-01`.
"""
nodelist = parser.parse(('end_br_menu_copyright',)) nodelist = parser.parse(('end_br_menu_copyright',))
parser.delete_first_token() parser.delete_first_token()
return BRMenuCopyrightNode(nodelist) return BRMenuCopyrightNode(nodelist)
...@@ -489,6 +604,11 @@ class BrMenuToggleNode(template.Node): ...@@ -489,6 +604,11 @@ class BrMenuToggleNode(template.Node):
self.target_expr = target_expr self.target_expr = target_expr
def render(self, context): def render(self, context):
"""
Nó interno para a tag `br_menu_toggle`.
Renderiza um botão para abrir o menu.
Lida com a resolução de variáveis para o label e o alvo (`target`).
"""
label = "Menu" label = "Menu"
target = "#main-navigation" target = "#main-navigation"
...@@ -526,6 +646,10 @@ class BrMenuToggleNode(template.Node): ...@@ -526,6 +646,10 @@ class BrMenuToggleNode(template.Node):
@register.tag @register.tag
def br_menu_toggle(parser, token): def br_menu_toggle(parser, token):
"""
Tag de bloco para criar um botão de "toggle" (alternar) para o menu.
Recebe os argumentos opcionais `label` e `target`.
"""
bits = token.split_contents() bits = token.split_contents()
label_expr = None label_expr = None
target_expr = None target_expr = None
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment