Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Websites UFRPE
django-dsgov
Commits
155f50e9
Commit
155f50e9
authored
Aug 26, 2025
by
Eduardo Silva
Browse files
ajustes nas tags e templates do dsgov
parent
98f84dfe
Changes
4
Show whitespace changes
Inline
Side-by-side
dsgov/templates/dsgov/components/breadcrumb.html
View file @
155f50e9
...
...
@@ -5,24 +5,30 @@
{% block content %}
<nav
class=
"br-breadcrumb"
aria-label=
"Breadcrumbs"
>
<ol
class=
"crumb-list"
role=
"list"
>
{% if items %}
<!-- Primeiro item (Home) - Apenas ícone -->
{% with items.0 as home %}
<li
class=
"crumb home"
>
<a
class=
"br-button circle"
href=
"
javascript:void(0)
"
>
<span
class=
"sr-only"
>
Página inicial
</span>
<a
class=
"br-button circle"
href=
"
{{ home.0 }}
"
>
<span
class=
"sr-only"
>
{{ home.1 }}
</span>
<i
class=
"fas fa-home"
></i>
</a>
</li>
<li
class=
"crumb"
><i
class=
"icon fas fa-chevron-right"
></i>
<a
href=
"javascript:void(0)"
>
Página Ancestral 01
</a>
{% endwith %}
<!-- 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
class=
"crumb"
><i
class=
"icon fas fa-chevron-right"
></i>
<a
href=
"javascript:void(0)"
>
Página Ancestral 02
</a>
</li>
<li
class=
"crumb"
><i
class=
"icon fas fa-chevron-right"
></i>
<a
href=
"javascript:void(0)"
>
Página Ancestral 03
</a>
</li>
<li
class=
"crumb"
data-active=
"active"
><i
class=
"icon fas fa-chevron-right"
></i>
<span
tabindex=
"0"
aria-current=
"page"
>
Página atual
</span>
{% endfor %}
{% endif %}
<!-- Página atual -->
<li
class=
"crumb"
data-active=
"active"
>
<i
class=
"icon fas fa-chevron-right"
></i>
<span
tabindex=
"0"
aria-current=
"page"
>
{{ current_title }}
</span>
</li>
</ol>
</nav>
{% endblock %}
\ No newline at end of file
dsgov/templates/dsgov/components/card_with_icon.html
View file @
155f50e9
...
...
@@ -6,12 +6,16 @@
<div
class=
"br-card hover"
style=
"cursor: pointer;"
>
<div
class=
"card-content"
>
<div
class=
"d-flex align-items-center"
>
{% if icon_
svg
%}
<i
mg
src=
"{% static icon_svg %}"
alt=
"ícone"
width=
"40"
height=
"40"
class=
"mr-3"
/
>
{% if icon_
class
%}
<i
class=
"fas {{ icon_class }} {{ icon_extra_class }}"
style=
"{{ icon_style }}"
></i
>
{% endif %}
<div>
<h4
class=
"mt-0 mb-1 text-primary"
style=
"font-family: 'Noto Sans', sans-serif;"
>
{{ title }}
</h4>
<p
style=
"font-family: 'Noto Sans', sans-serif; color: #5C5C5C;"
>
{{ text }}
</p>
<h4
class=
"{{ title_class }}"
style=
"{{ title_style }}"
>
{{ title }}
</h4>
<p
class=
"{{ text_class }}"
style=
"{{ text_style }}"
>
{{ text }}
</p>
</div>
</div>
</div>
...
...
dsgov/templatetags/br_components.py
View file @
155f50e9
...
...
@@ -2,11 +2,17 @@ from django import template
from
django.utils.html
import
format_html
from
django.templatetags.static
import
static
from
django.template.loader
import
render_to_string
from
urllib.parse
import
urlencode
,
parse_qs
register
=
template
.
Library
()
@
register
.
simple_tag
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
(
"""
<link rel="stylesheet" href="{}">
...
...
@@ -18,6 +24,10 @@ def br_stylesheets():
@
register
.
simple_tag
def
br_scripts
():
"""
Renderiza o script principal do DSGov.
Inclui o bundle JS como módulo, necessário para componentes interativos.
"""
return
format_html
(
"""
<script type="module" src="{}"></script>
...
...
@@ -25,130 +35,209 @@ def br_scripts():
static
(
'dsgov/dist/js/bundle.js'
)
)
@
register
.
simple_tag
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
''
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
''
return
format_html
(
'<button type="{}" class="{}">{}{}</button>'
,
button_type
,
classes
,
icon_html
,
text
)
@
register
.
simple_tag
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
""
close_button_html
=
""
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
""
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
)
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
)
return
format_html
(
'<div class="d-flex align-items-center flex-wrap gap-2">{}</div>'
,
tag_html
)
@
register
.
simple_tag
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'
classes
=
f
'br-input
{
density_class
}
{
extra_classes
}
'
.
strip
()
disabled_attr
=
'disabled'
if
disabled
else
''
readonly_attr
=
'readonly'
if
readonly
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
''
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
:
input_html
=
format_html
(
'<input type="{}" id="{}" placeholder="{}" value="{}" class="{}" {} {}/>'
,
input_type
,
input_id
,
placeholder
,
value
,
extra_classes
,
disabled_attr
,
readonly_attr
)
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
)
@
register
.
simple_tag
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
=
""
):
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
)
input_html
=
format_html
(
'<input type="{}" id="{}" placeholder="{}" value="{}" class="{}" {} {}/>'
,
input_type
,
input_id
,
placeholder
,
value
,
extra_classes
,
disabled_attr
,
readonly_attr
)
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
)
@
register
.
simple_tag
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
=
{
"title"
:
title
,
"items"
:
items
,
}
return
render_to_string
(
"dsgov/components/list.html"
,
context
)
@
register
.
simple_tag
def
br_carousel
(
slides
=
None
,
responsivo
=
True
):
context
=
{
'slides'
:
slides
or
[],
'responsivo'
:
responsivo
}
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
=
""
):
@
register
.
inclusion_tag
(
"dsgov/components/breadcrumb.html"
)
def
br_breadcrumb
(
items
=
None
,
current_title
=
""
):
"""
Renderiza o componente de breadcrumb DSGov a partir de um template.
Uso no template:
{% br_breadcrumb items=breadcrumb_list current_title=page.title %}
"""
return
{
'pages'
:
pages
,
"items"
:
items
or
[],
"current_title"
:
current_title
,
}
@
register
.
simple_tag
def
br_pagination
(
pages
=
""
):
context
=
{
'pages'
:
pages
,
}
def
br_pagination
(
total_pages
=
1
,
current_page
=
1
,
base_url
=
"?page="
,
extra_params
=
""
):
"""
Renderiza um componente de paginação DSGov preservando parâmetros GET.
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
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
=
{
'title'
:
title
,
'text'
:
text
,
'icon_svg'
:
icon_path
"title"
:
title
,
"text"
:
text
,
"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
)
dsgov/templatetags/br_menu_tags.py
View file @
155f50e9
from
django
import
template
from
django.utils.safestring
import
mark_safe
from
django.utils.html
import
format_html
from
django.utils.safestring
import
mark_safe
from
django.template.base
import
token_kwargs
register
=
template
.
Library
()
@
register
.
tag
(
name
=
'br_menu_row'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuRowNode
(
nodelist
)
...
...
@@ -21,6 +25,11 @@ class BRMenuRowNode(template.Node):
@
register
.
tag
(
name
=
'br_menu'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuNode
(
nodelist
)
...
...
@@ -44,6 +53,11 @@ class BRMenuNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_header'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuHeaderNode
(
nodelist
)
...
...
@@ -67,6 +81,11 @@ class BRMenuHeaderNode(template.Node):
@
register
.
simple_tag
(
name
=
'br_menu_header_logo'
)
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"/>'
)
class
BrMenuTitleNode
(
template
.
Node
):
...
...
@@ -79,6 +98,10 @@ class BrMenuTitleNode(template.Node):
@
register
.
tag
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'
])
parser
.
delete_first_token
()
return
BrMenuTitleNode
(
nodelist
)
...
...
@@ -89,6 +112,11 @@ class BrMenuTitleLogoNode(template.Node):
self
.
alt_expr
=
alt_expr
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,iVBORw0KGgoAAAANSUhEUgAAAMwAAABgCAYAAABR/J1nAAAAAXNSR0IArs4c6QAADK1JREFUeAHtXX+MHFUd/77Z3dlWaAFpr/Rut1o1BgEJig2Weu0uLWIi1NIUTeAPDKIBsQ2xJYZEbFNioijRoGmjTcBYDL9SFGlFTGmvPyggVlRoQKKk9H7U0mKrLdKZu93n5+3dm5s9Zmd372bnZma/k8y+N+/XvO/nvc9834/vzohsvijJ47B6dwqPYOL0w6gwPsM4tEt/0HIaXqTgMEaAEfBGwFOLeCflUEagfRFgDdO+bc+STwABHpJNADzO2n4IMGHar81Z4okgoMZmenw2kXI4LyPQDgiwhmmHVmYZA0OACRMYlFxQOyDAhGmHVmYZA0OACRMYlFxQOyDAhGmHVmYZA0OAd/oDg5ILSjICeiWZNUySW5llCxwBJkzgkHKBSUaACZPk1mXZAkeACRM4pFxgkhFgwiS5dVm24BFgW7LgMeUSk4sAa5jkti1L1gIEmDAtAJWLTC4CTJjkti1L1gIEmDAtAJWLTC4CTJjkti1L1gIE2JasBaBykclDgG3JktemLFEICPCQLASQ+RbJQYAJk5y2ZElCQIAJEwLIfIvkIJBulSjZruLnSciVksSnhKBzW3WfIMuVkt5GXfdTme6z+nduC7JsLisZCAg9+6/1NvrxiJnpKvzQMMTq8eSNSp5yWd472N+zJir14XpEA4HAh2RKs8SdLKpplAwVLRmNduJaRASBwAlDBq2KiGwTrwaGlBMvhEtIEgKBEwbzgEuTApCafyVFFpYjGAQCJ0wTE/w3SNIOnG8FI0rwpTQhS/A35xIjiUDLVsm8pJU4YIuzwZKptdT/zNs6jdlZOF8YtIGEKOowdhmBKCIQuC2ZXnUbK6wiCwhxrd2784mxcSPXAqtrP4jagkGQq4c15PYMzuSLNxHJj6tIoyR3WAO7nvRMyIGhIKD7dWgapqJZapNFCS0H+0/eaeamLRZCXBIKChG+iSC5VJD4QgUYQwzCZcJEoL0Cn8PUkqkyDKsV6YTvR8cQdzuX7GEEIoZAWIR5wz1n8cPALpde9IvnOEZgMhEIhzCSDjYs5MDufonRWcPpfRKinNM+0RzFCDSNQDiEIbqo0ZqZ53Wfj7F7ptH0tdJJogds25xRKsluLDf8u1Y6DmcEmkHAULN/vQLQTMam0grqUEvHjeSRqdTCRtL5pQFB7sdq3FfoyB/eGRro2SvLpSXtS5pCms4unO2H13viZhbOJLrQfE94swEfLEyhGQumNZstiunVaqk6w1slU/ssRItx4uFf4zive6YhaH2N2IaCK2Tp23kzEjv3GRzY/VKmc+ESMlLbsRn5/oYKikEiLD3fK6TsVlXFKuT1Vl/PPyrVnrVwbiZt3GYYtBw7X3Mgc0qeWYSWlfuQ8E67t+eVseKluxYVDcO4HeXNx/L/TJnvsIk6XgGKW+2+GWiTx0pj83hdZ3LFy7DCtwb1+bQcoi4x1RQyXziOtHtR9karb9dTOp+ZK8IiXM7EquhxdMardHiU3bCGZGhRUVT7LESXeg+3QJZsOvWQaqzxAuZFFl2WIk3SNA064EfR2eapU1LpfUrWbG7RSjNjvD68nyXmKrKocPWgQLqrSYq/mPnCMhVWOaAFzHzxkZRh7EAnX6rxh9/E+Unk+042d3RbXU0x67NnmLnC43jgPY/7rEA5ObgoQpFZnIPzGhLG75Dm11rjIfYSJJlHUn5iuDLR/w2PMMBCNSL2Wf6IJ8ty6lyYV0GYs1wAIt0CshwAyEoDjevwI4suMImk0bIpF7jeg055HzphGniUsVf8Gs6XcA7pdOikKWiNX1LnZ+aoYVe2JLajV39RxUMl/xdpn4fvsE5fcYW4ypyavr0qzH2Bh51pDu7Cfa/Vwbh/CeX9GeejIEQPFmCUlkETi2XmNPEsnbPkLJ02Tm5oQzINCgBTm5Jbsim0W64whOt05TGkE4zDbYQsutikDs9Ipq+GedEdiigYEm2wT9FddKLnREVuzCOyUzKPord+Tl0D82mmkb6ech1qeLoAHbpXCrES877f4roylE13FpYYKbEFbTO9kofErRgdfI9I7ZVVH2YmtQnpHKNbkG6rkEOrrb69r4+mBDm7Zn4d97kLpL0ge8bQw6hJRfuNpom+L1QNMxYORZaxYc1eN0MWXXYiNY0h16GjKr2i5jIrHbIooY89e9LqO7kUXPiXxgCddhX8q5HlNesUXTxislQhi0qDxZLtROVbdHp07tnp/PQrRq+HfVjM+ZK2SBgOkXvsvpPLrX43WVTMAdvq7/mxKNPloGT/CHlnDeeJz6+hZ//xqfJoTcdDFp07aaSpLMVL+q490POIlrHa3T8IvH4xGiZmg0DvQDNcU0Wu0QRk9x7bAu1zTAcJSR/Qfsc1aLXjl3TIsu0VXlpIp7EGdv5dlkpXBrXXpstttatXkydVw2gh0ZCbrVJpDpXL31TPSB3u506ELLrcJJEGquE/tk3f17J5uoJecIdjeLTJWVlzRzj+A1gpoz/pSwz1OrVfudlc4SMYJcxzhd1KR/bV/buGfXj3q7DE/akrX2y8k06YkY5/Iw3s7rX6d/1IivLN9UgTBFl0CynSwB/LxtMyKBcrZpvpaM8pd9hYvyyTMyRTcYMk1FK/74H/Yzh5oMWqCFMmWdSZVZtZp+09+rqei7rE8iUjk0oYr44/2LvrAT/SeOWp1zj149F8MT+w31K9suUhD5Z8neFVJTpV7vdIVh0kxVEdAC02RfuVK8jIOdeCXlVzJec6oZ5JI4xfx69FGr88CW2fQMWyBsvVm48HpzqT/No3ktV5XAmFkO5J+35XVGK9k0KYRjr+WNI0kiexrRRRwWRZHHKqJmmG40+wJ63tyNRqWRhyNtPxFWky+UUYn4vL7b6er6F+DTwRw5CC76EQwCLA39TviP/iiiehP5ofoWqYZsiicVekwUrOV3HNZNGgRMS1ysbLTlVgCmPOXvgx57qOxzDkuE2g6hTd0ujQCIMNst/YY4wiWyoZF956BA7veBNPsQP6RiJt/Az+hkYqWHH7hs4XJzc0wgCUv+KMqpZoqJGDbViY3VdM6AMwow+2Yk2VVi5Jl42Z6Ibx55p6BZhdhbuRZkG9dFGMD5MwUZR/0upk5unxbL7DMvMdsV6KVSY02LUffROQMO6BRfKDntbNnYUZ2Vzx58IQ38bw3GVnNmnN0PSNJ2zL1fQdOUPiELBL5ZWmYXwIu/6V10LBvSE7xbwSxrX78HeCF4UhbQwtLsJoTVkzTwdZNsNC9FewvPx93MBI69l/3CrO9Y0QArDSsHPzLzMpuxFzkxsrNcO/bOFfhhnNMjWtcY15N2Iue1u6q3gF3sMdm0OvJoemYQBZAap6XRQRUnWLYr1iVae+596F4dmXza5F22CJvBRaZj7q/2Elg7KiBsa7ZVludIxDVZBDI5h1xuRwET+YGmsmBlPa5JfCGngCbdCxeFY2Y51l9U97k+gpy10SHp43gFQPqjDw6WXss0V6H0f368A1DMan6ite57rBiatfyRLXukei3m89cwQsOeJZF0HuPZt/eqaJYGDgo0iQJTE2RdjJdkzbI9h2EalSIQ1tsZbyC6osmf0rd6F6X8BNOg00zR7tj7obOGHU9yGjLnTD9ZPiJw2nbceEuflTszl6Eh1+XVZmXjBz3fWHVeplGfmOxzB/ma0gw5L0Cetde1Nc4Av8vWTqY6rq+5BxAaBWPZUM/GHYWuiMhPc9dxp/QhveR4JpDFFqLyb91xFdhxVjjwMvPjEz9l5ol6U6FnP/b8XhbwFqLqvOlnwUVoHBX1HWXSLhLl7TlB2irVgZW+xIio9kYdnraVjNHsIrOf6HxTDswahXKQm8Fmp0MRlzxPVYYl7r5IuBp2WEiYHsXMXgEDAwj7kDpFkP7dHAGzPlQbyEaVUcv3nDhAmu03BJMH3JCFqh3riJyclc/G8f8xSJFwyK49Ay6q/O6p0CT9gp+TQd7Inni+LV+rJeY+YWZwRagEDwC0stqGSjRSZKmEaF5nShIhD79yW40cKQkw9GgBGoh4AehbGGqYcUxzMCLgSYMC4w2MsI1EOACVMPIY5nBFwIMGFcYLCXEaiHABOmHkIczwi4EeB9GDca7GcE/BFgDeOPD8cyAlUIMGGq4OALRsAfASaMPz4cywhUIcCEqYKDLxgBfwSYMP74cCwjUIUA25JVwcEXjIA3AmxL5o0LhzICvgjwkMwXHo5kBKoRYMJU48FXjIAvAkwYX3g4khGoRoAJU40HXzEC/giwLZk/PhzLCLgRYA3jRoP9jEAdBJgwdQDiaEbAjQATxo0G+xmBOgjU/NyF3tkcm7/W91I4/TBSjM8wDkntD6xhxj4R+JoR8EHg/z6seDvVOnj4AAAAAElFTkSuQmCC"
alt
=
"Imagem ilustrativa"
try
:
...
...
@@ -114,17 +142,29 @@ class BrMenuTitleTextNode(template.Node):
self
.
nodelist
=
nodelist
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
)
return
format_html
(
'<span>{}</span>'
,
content
)
@
register
.
tag
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'
])
parser
.
delete_first_token
()
return
BrMenuTitleTextNode
(
nodelist
)
@
register
.
tag
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
()
src_expr
=
None
alt_expr
=
None
...
...
@@ -139,6 +179,11 @@ def br_menu_title_logo(parser, token):
@
register
.
tag
(
name
=
'br_menu_body'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuBodyNode
(
nodelist
)
...
...
@@ -151,8 +196,13 @@ class BRMenuBodyNode(template.Node):
content
=
self
.
nodelist
.
render
(
context
)
return
mark_safe
(
f
'<nav class="menu-body" role="tree">
{
content
}
</nav>'
)
@
register
.
tag
(
name
=
'br_menu_folder'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuFolderNode
(
nodelist
)
...
...
@@ -167,6 +217,12 @@ class BRMenuFolderNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_item'
)
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
()
tag_name
=
bits
[
0
]
...
...
@@ -228,6 +284,11 @@ class BRMenuItemNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_divider_item'
)
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
:
bits
=
token
.
split_contents
()
tag_name
=
bits
[
0
]
...
...
@@ -267,6 +328,10 @@ class BRMenuDividerItemNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_footer'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuFooterNode
(
nodelist
)
...
...
@@ -284,11 +349,19 @@ class BRMenuFooterLogosNode(template.Node):
self
.
nodelist
=
nodelist
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
()
return
format_html
(
'<div class="menu-logos">{}</div>'
,
mark_safe
(
content
))
@
register
.
tag
(
name
=
'br_menu_footer_logos'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuFooterLogosNode
(
nodelist
)
...
...
@@ -299,6 +372,11 @@ class BRMenuLogoNode(template.Node):
self
.
alt_expr
=
alt_expr
or
template
.
FilterExpression
(
'"Imagem ilustrativa"'
,
parser
=
None
)
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
:
src
=
self
.
src_expr
.
resolve
(
context
)
except
template
.
VariableDoesNotExist
:
...
...
@@ -313,6 +391,10 @@ class BRMenuLogoNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_logo'
)
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
()
src_expr
=
None
alt_expr
=
None
...
...
@@ -330,6 +412,10 @@ def do_br_menu_logo(parser, token):
@
register
.
tag
(
name
=
"br_menu_links"
)
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"
,))
parser
.
delete_first_token
()
return
BRMenuLinksNode
(
nodelist
)
...
...
@@ -344,6 +430,10 @@ class BRMenuLinksNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_list'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuListNode
(
nodelist
)
...
...
@@ -358,6 +448,9 @@ class BRMenuListNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_list_item'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuListItemNode
(
nodelist
)
...
...
@@ -372,6 +465,11 @@ class BRMenuListItemNode(template.Node):
@
register
.
tag
(
name
=
"br_menu_link"
)
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
()
href_expr
=
None
icon_expr
=
None
...
...
@@ -417,6 +515,10 @@ class BRMenuLinkNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_social_network'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuSocialNetworkNode
(
nodelist
)
...
...
@@ -435,6 +537,10 @@ class BRMenuSocialNetworkNode(template.Node):
@
register
.
tag
(
name
=
'br_menu_social_network_title'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuSocialNetworkTitleNode
(
nodelist
)
...
...
@@ -449,6 +555,11 @@ class BRMenuSocialNetworkTitleNode(template.Node):
@
register
.
simple_tag
(
name
=
'br_menu_social_network_icons'
,
takes_context
=
True
)
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
href
=
href
.
strip
(
'"
\'
'
)
...
...
@@ -468,6 +579,10 @@ def br_menu_social_network_icons(context, href, icon, extra_classes=""):
@
register
.
tag
(
name
=
'br_menu_copyright'
)
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'
,))
parser
.
delete_first_token
()
return
BRMenuCopyrightNode
(
nodelist
)
...
...
@@ -489,6 +604,11 @@ class BrMenuToggleNode(template.Node):
self
.
target_expr
=
target_expr
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"
target
=
"#main-navigation"
...
...
@@ -526,6 +646,10 @@ class BrMenuToggleNode(template.Node):
@
register
.
tag
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
()
label_expr
=
None
target_expr
=
None
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment