Commit b8d199b1 authored by Eduardo Silva's avatar Eduardo Silva
Browse files

criacao das tags do header e do template de exemplo do header #6

parent c73e9710
{% extends "dsgov/base.html" %}
{% load br_components %}
{% load static %}
{% block content %}
<header class="br-header mb-4 {{ extra_classes }}" id="header" data-sticky="data-sticky">
<div class="container-lg">
<div class="header-top">
<div class="header-logo">
<img src="{{ logo_url }}" alt="logo"/>
<span class="br-divider vertical"></span>
<div class="header-sign" style="{{ header_sign_style }}">{{ title_extra }}</div>
</div>
<div class="header-actions">
<div class="header-links dropdown">
<button class="br-button circle small" type="button" data-toggle="dropdown" aria-label="Abrir Acesso Rápido">
<i class="fas fa-ellipsis-v" aria-hidden="true" style="{{ links_style }}"></i>
</button>
<div class="br-list">
<div class="header">
<div class="title" style="{{ links_style }}">Acesso Rápido</div>
</div>
<a class="br-item {{ extra_classes }}" href="javascript:void(0)" style="{{ links_style }}">Link de acesso 1</a>
<a class="br-item {{ extra_classes }}" href="javascript:void(0)" style="{{ links_style }}">Link de acesso 2</a>
<a class="br-item {{ extra_classes }}" href="javascript:void(0)" style="{{ links_style }}">Link de acesso 3</a>
<a class="br-item {{ extra_classes }}" href="javascript:void(0)" style="{{ links_style }}">Link de acesso 4</a>
<select class="bg-blue-warm-vivid-90 rounder-lg border-solid-none" name="languages" id="languages" style="{{ items_style }}" onchange="changeLanguage()">
<option value="pt-br" selected>PT</option>
<option value="en">EN</option>
<option value="es">ES</option>
</select>
</div>
</div>
<span class="br-divider vertical mx-half mx-sm-1"></span>
<div class="header-functions dropdown">
<button class="br-button circle small" type="button" data-toggle="dropdown" aria-label="Abrir Funcionalidades do Sistema">
<i class="fas fa-th" aria-hidden="true" style="{{ links_style }}"></i>
</button>
<div class="br-list">
<div class="header">
<div class="title" style="{{ title_style }}">Funcionalidades do Sistema</div>
</div>
<div class="br-item {{ extra_classes }}">
<button class="br-button circle small" type="button" aria-label="Funcionalidade 1">
<i class="fas fa-chart-bar" aria-hidden="true" style="{{ items_style }}"></i>
<span class="text" style="{{ title_style }}">Funcionalidade 1</span>
</button>
</div>
<div class="br-item {{ extra_classes }}">
<button class="br-button circle small" type="button" aria-label="Funcionalidade 2">
<i class="fas fa-headset" aria-hidden="true" style="{{ items_style }}"></i>
<span class="text" style="{{ title_style }}">Funcionalidade 2</span>
</button>
</div>
<div class="br-item {{ extra_classes }}">
<button class="br-button circle small" type="button" aria-label="Funcionalidade 3">
<i class="fas fa-comment" aria-hidden="true" style="{{ items_style }}"></i>
<span class="text" style="{{ title_style }}">Funcionalidade 3</span>
</button>
</div>
<div class="br-item {{ extra_classes }}">
<button class="br-button circle small" type="button" aria-label="Funcionalidade 4">
<i class="fas fa-adjust" aria-hidden="true" style="{{ items_style }}"></i>
<span class="text" style="{{ title_style }}">Funcionalidade 4</span>
</button>
</div>
</div>
</div>
<div class="header-search-trigger">
<button class="br-button circle" type="button" aria-label="Abrir Busca" data-toggle="search" data-target=".header-search">
<i class="fas fa-search" aria-hidden="true" style="{{ items_style }}"></i>
</button>
</div>
<div class="header-login">
<div class="header-sign-in">
<button class="br-sign-in small" type="button" data-trigger="login">
<i class="fas fa-user" aria-hidden="true"></i>
<span class="d-sm-inline">{{ label_button_login }}</span>
</button>
</div>
<div class="header-avatar"></div>
</div>
</div>
</div>
<div class="header-bottom">
<div class="header-menu">
<div class="header-menu-trigger" id="header-navigation">
<button class="br-button small circle" type="button" aria-label="Menu" data-toggle="menu" data-target="#main-navigation" id="navigation">
<i class="fas fa-bars" aria-hidden="true" style="color: #FFFFFF;"></i>
</button>
</div>
<div class="header-info">
<div class="header-title" style="{{ title_style }}">{{ title }}</div>
<div class="header-subtitle" style="{{ title_style }}">{{ subtitle }}</div>
</div>
</div>
<div class="header-search" id="main-searchbox">
<div class="br-input has-icon">
<label for="searchbox">Texto da pesquisa</label>
<input id="searchbox" type="text" placeholder="{{ search_placeholder }}"/>
<button class="br-button circle small" type="button" aria-label="Pesquisar">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
<button class="br-button circle search-close ml-1" type="button" aria-label="Fechar Busca" data-dismiss="search">
<i class="fas fa-times" aria-hidden="true" style="{{ links_style }}"></i>
</button>
</div>
</div>
</div>
</header>
{% endblock %}
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 django.utils.safestring import mark_safe
from django.template.base import token_kwargs
......@@ -152,9 +150,23 @@ class ItemNode(template.Node):
# --- TAGS DE LOGO, REDES SOCIAIS E COPYRIGHT DO FOOTER ---
@register.simple_tag
def br_logo(src, alt=""):
"""Tag Simples e direta para o logo."""
return format_html('<div class="logo"><img src="{}" alt="{}"/></div>', src, alt)
def br_logo(src, alt="", extra_classes="", extra_styles=""):
"""
Renderiza o logo com ou sem wrapper <div class="logo">.
Se o usuário fornecer extra_classes ou extra_styles, assume que quer controle total
e remove o wrapper por padrão.
"""
img_html = format_html(
'<img src="{}" alt="{}" class="{}" style="{}"/>',
src, alt, extra_classes, extra_styles
)
# Se o usuário passou estilos ou classes, damos controle total (sem <div class="logo">)
if extra_classes or extra_styles:
return img_html
else:
return format_html('<div class="logo">{}</div>', img_html)
@register.tag(name='br_footer_social_section')
def do_footer_social_section(parser, token):
......
from django import template
from django.utils.safestring import mark_safe
from django.utils.html import format_html
register = template.Library()
# Tag simples: <div class="header-top">...</div>
class SimpleBlockNode(template.Node):
def __init__(self, nodelist, tag_open, tag_close):
self.nodelist = nodelist
self.tag_open = tag_open
self.tag_close = tag_close
def render(self, context):
content = self.nodelist.render(context)
return format_html('{}{}{}', mark_safe(self.tag_open), mark_safe(content), mark_safe(self.tag_close))
def create_simple_block(name, tag_open, tag_close):
def tag_func(parser, token):
nodelist = parser.parse(['end_' + name])
parser.delete_first_token()
return SimpleBlockNode(nodelist, tag_open, tag_close)
register.tag(name, tag_func)
# Header raiz
create_simple_block('br_header', '<header class="br-header"><div class="container-lg">', '</div></header>')
create_simple_block('br_header_top', '<div class="header-top">', '</div>')
create_simple_block('br_header_bottom', '<div class="header-bottom">', '</div>')
create_simple_block('br_header_list', '<div class="header">', '</div>')
create_simple_block('br_list_title', '<div class="title">', '</div>')
# Ações
class ActionsNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
content = self.nodelist.render(context)
return format_html('<div class="header-actions">{}</div>', mark_safe(content))
@register.tag
def br_header_actions(parser, token):
nodelist = parser.parse(['end_br_header_actions'])
parser.delete_first_token()
return ActionsNode(nodelist)
@register.simple_tag
def br_header_logo(src, alt, signature=""):
logo_html = format_html('<img src="{}" alt="{}" />', src, alt)
if signature:
return format_html(
'''<div class="header-logo">
{}
<span class="br-divider vertical"></span>
<div class="header-sign">{}</div>
</div>''',
logo_html,
mark_safe(signature)
)
else:
return format_html('<div class="header-logo">{}</div>', logo_html)
class DropdownNode(template.Node):
def __init__(self, nodelist, tag_name, class_name):
self.nodelist = nodelist
self.tag_name = tag_name
self.class_name = class_name
def render(self, context):
content = self.nodelist.render(context)
html = f'''
<div class="{self.tag_name} {self.class_name}">
<button class="br-button circle small" type="button" data-toggle="dropdown" aria-label="Abrir {self.tag_name.replace('-', ' ').title()}">
<i class="fas {'fa-ellipsis-v' if 'links' in self.tag_name else 'fa-th'}" aria-hidden="true"></i>
</button>
<div class="br-list">
{content}
</div>
</div>
'''
if 'links' in self.tag_name:
html += '<span class="br-divider vertical mx-half mx-sm-1"></span>'
return mark_safe(html)
def dropdown_tag(name, tag_class):
def tag_func(parser, token):
bits = token.split_contents()
class_name = "dropdown"
if len(bits) > 1:
for bit in bits[1:]:
if bit.startswith('class='):
class_name = bit.split('=')[1].strip('"\'')
nodelist = parser.parse([f'end_{name}'])
parser.delete_first_token()
return DropdownNode(nodelist, tag_class, class_name)
register.tag(name, tag_func)
dropdown_tag('br_header_links', 'header-links')
dropdown_tag('br_header_functions', 'header-functions')
class ItemNode(template.Node):
def __init__(self, nodelist, href):
self.nodelist = nodelist
self.href = href
def render(self, context):
content = self.nodelist.render(context)
href = self.href.strip('"\'')
try:
resolved_href = template.Variable(href).resolve(context)
except template.VariableDoesNotExist:
resolved_href = href
return format_html('<a class="br-item" href="{}">{}</a>', resolved_href, mark_safe(content))
@register.tag
def br_item(parser, token):
try:
tag_name, href = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError('%r tag requires href argument' % token.contents.split()[0])
nodelist = parser.parse(['end_br_item'])
parser.delete_first_token()
return ItemNode(nodelist, href)
@register.simple_tag
def br_function_item(icon, label):
return format_html('''
<div class="br-item">
<button class="br-button circle small" type="button" aria-label="{0}">
<i class="fas {1}" aria-hidden="true"></i>
<span class="text">{0}</span>
</button>
</div>
''', label, icon)
@register.simple_tag
def br_header_search_trigger():
return mark_safe('''
<div class="header-search-trigger">
<button class="br-button circle" type="button" aria-label="Abrir Busca" data-toggle="search" data-target=".header-search">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
''')
@register.simple_tag
def br_header_login():
return mark_safe('<div class="header-login">')
@register.simple_tag
def end_br_header_login():
return mark_safe('</div>')
@register.simple_tag
def br_button():
return mark_safe('''
<div class="header-sign-in">
<button class="br-sign-in small" type="button" data-trigger="login">
<i class="fas fa-user" aria-hidden="true"></i>
<span class="d-sm-inline">Entrar</span>
</button>
</div>
''')
@register.simple_tag
def br_header_avatar(icon=""):
return format_html('<div class="header-avatar">{}</div>', mark_safe(icon))
@register.simple_tag
def br_header_menu():
return mark_safe('''
<div class="header-menu">
<div class="header-menu-trigger">
<button class="br-button small circle" type="button" aria-label="Menu" data-toggle="menu" data-target="#main-navigation" id="navigation">
<i class="fas fa-bars" aria-hidden="true"></i>
</button>
</div>
<div class="header-info">
<div class="header-title">Título do Header</div>
<div class="header-subtitle">Subtítulo do Header</div>
</div>
</div>
''')
@register.simple_tag
def br_header_search():
return mark_safe('''
<div class="header-search">
<div class="br-input has-icon">
<label for="searchbox-114">Texto da pesquisa</label>
<input id="searchbox-114" type="text" placeholder="O que você procura?"/>
<button class="br-button circle small" type="button" aria-label="Pesquisar">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
<button class="br-button circle search-close ml-1" type="button" aria-label="Fechar Busca" data-dismiss="search">
<i class="fas fa-times" aria-hidden="true"></i>
</button>
</div>
''')
{% extends "dsgov/base.html" %}
{% load br_components %}
{% load br_header_tags %}
{% load static %}
{% block title %}
......@@ -7,8 +7,43 @@
{% endblock %}
{% block content %}
<div class="container">
{% static '/dsgov/images/logo.png' as logo_path %}
{% br_header title="Universidade Federal Rural de Pernambuco" logo_url=logo_path links=lista extra_classes="bg-blue-warm-vivid-90" links_style="color: #FFFFFF;" title_extra="UFRPE" title_style="color: #FFFFFF;" items_style="color: #FFFFFF;" search_placeholder="O que você procura?" label_button_login="Entrar" header_sign_style="color: #FFFFFF; font-weight: bold;" %}
</div>
{% br_header %}
{% br_header_top %}
{% br_header_logo 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="logo" signature="Assinatura" %}
{% br_header_actions %}
{% br_header_links class="dropdown" %}
{% br_header_list %}
{% br_list_title %}Acesso Rápido{% end_br_list_title %}
{% end_br_header_list %}
{% br_item "javascript:void(0)" %}Link de acesso 1{% end_br_item %}
{% br_item "javascript:void(0)" %}Link de acesso 2{% end_br_item %}
{% br_item "javascript:void(0)" %}Link de acesso 3{% end_br_item %}
{% br_item "javascript:void(0)" %}Link de acesso 4{% end_br_item %}
{% end_br_header_links %}
{% br_header_functions class="dropdown" %}
{% br_header_list %}
{% br_list_title %}Funcionalidades do Sistema{% end_br_list_title %}
{% end_br_header_list %}
{% br_function_item "fa-chart-bar" "Funcionalidade 1" %}
{% br_function_item "fa-headset" "Funcionalidade 2" %}
{% br_function_item "fa-comment" "Funcionalidade 3" %}
{% br_function_item "fa-adjust" "Funcionalidade 4" %}
{% end_br_header_functions %}
{% br_header_search_trigger %}
{% br_header_login %}
{% br_button %}
{% br_header_avatar %}
{% end_br_header_login %}
{% end_br_header_actions %}
{% end_br_header_top %}
{% br_header_bottom %}
{% br_header_menu %}
{% br_header_search %}
{% end_br_header_bottom %}
{% end_br_header %}
{% endblock %}
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