Update base page layout for Tabler

This commit is contained in:
Jeremy Stretch 2023-12-29 16:30:26 -05:00
parent 76d834476f
commit 69f849d4e6
6 changed files with 248 additions and 300 deletions

View File

@ -5,38 +5,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html <html
lang="en" lang="en"
{% if preferences|get_key:'ui.colormode' == 'dark' %}
data-bs-theme="dark"
{% endif %}
data-netbox-url-name="{{ request.resolver_match.url_name }}" data-netbox-url-name="{{ request.resolver_match.url_name }}"
data-netbox-base-path="{{ settings.BASE_PATH }}" data-netbox-base-path="{{ settings.BASE_PATH }}"
{% with preferences|get_key:'ui.colormode' as color_mode %}
{% if color_mode == 'dark'%}
data-netbox-color-mode="dark"
{% elif color_mode == 'light' %}
data-netbox-color-mode="light"
{% else %}
data-netbox-color-mode="unset"
{% endif %}
{% endwith %}
> >
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover" />
name="viewport"
content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover"
/>
{# Page title #} {# Page title #}
<title>{% block title %}{% trans "Home" %}{% endblock %} | NetBox</title> <title>{% block title %}{% trans "Home" %}{% endblock %} | NetBox</title>
<script
type="text/javascript"
src="{% static 'setmode.js' %}"
onerror="window.location='{% url 'media_failure' %}?filename=setmode.js'">
</script>
<script type="text/javascript"> <script type="text/javascript">
(function () {
initMode()
})();
window.CSRF_TOKEN = "{{ csrf_token }}"; window.CSRF_TOKEN = "{{ csrf_token }}";
</script> </script>
@ -72,32 +54,6 @@
</head> </head>
<body> <body>
<script type="text/javascript">
function checkSideNav() {
// Check localStorage to see if the sidebar should be pinned.
var sideNavRaw = localStorage.getItem('netbox-sidenav');
// Determine if the device has a small screeen. This media query is equivalent to
// bootstrap's media-breakpoint-down(lg) breakpoint mixin, which is what the sidenav's
// CSS uses.
var isSmallScreen = window.matchMedia('(max-width: 991.98px)').matches;
if (typeof sideNavRaw === 'string') {
var sideNavState = JSON.parse(sideNavRaw);
if (sideNavState.pinned === true && !isSmallScreen) {
// If the sidebar should be pinned and this is not a small screen, set the appropriate
// body attributes prior to the rest of the content rendering. This prevents
// jumpy/glitchy behavior on page reloads.
document.body.setAttribute('data-sidenav-pinned', '');
document.body.setAttribute('data-sidenav-show', '');
document.body.removeAttribute('data-sidenav-hidden');
} else {
document.body.removeAttribute('data-sidenav-pinned');
document.body.setAttribute('data-sidenav-hidden', '');
}
}
}
window.addEventListener('resize', function(){ checkSideNav() });
checkSideNav();
</script>
{# Page layout #} {# Page layout #}
{% block layout %}{% endblock %} {% block layout %}{% endblock %}

View File

@ -1,6 +1,7 @@
{# Base layout for the core NetBox UI w/navbar and page content #} {# Base layout for the core NetBox UI w/navbar and page content #}
{% extends 'base/base.html' %} {% extends 'base/base.html' %}
{% load helpers %} {% load helpers %}
{% load navigation %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
@ -14,56 +15,108 @@ Blocks:
{% block layout %} {% block layout %}
<div class="container-fluid px-0"> <div class="page">
<main class="layout">
{# Sidebar #} {# Sidebar #}
{% include 'base/sidenav.html' %} <aside class="navbar navbar-vertical navbar-expand-lg" data-bs-theme="dark">
<div class="container-fluid">
{# Body #} {# Header icon #}
<div class="content-container" tabindex="-2"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar-menu" aria-controls="sidebar-menu" aria-expanded="false" aria-label="Toggle navigation">
{# NetBox Logo, only visible when printing #}
<div class="p-2 printonly">
<img src="{% static 'netbox_logo.svg' %}" alt="{% trans "NetBox logo" %}" width="200px" />
</div>
{# Top bar #}
<nav class="navbar navbar-light sticky-top flex-md-nowrap p-1 mb-3 search container-fluid noprint">
{# Mobile Navigation #}
<div class="nav-mobile">
<div class="nav-mobile-top">
<a class="sidebar-logo p-2 d-block" href="{% url 'home' %}">
<img src="{% static 'netbox_logo.svg' %}" alt="{% trans "NetBox logo" %}" height="40" />
</a>
<button type="button" aria-label="Toggle Navigation" class="navbar-toggler sidenav-toggle-mobile">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
</div> <h1 class="navbar-brand navbar-brand-autodark">
<div class="d-flex my-1 flex-grow-1 justify-content-center w-100"> <a href="{% url 'home' %}">
{% include 'inc/searchbar.html' %} <img src="{% static 'netbox_logo.svg' %}" height="32" alt="{% trans "NetBox Logo" %}" class="navbar-brand-image">
</div> </a>
</h1>
{# Navigation menu #}
<div class="collapse navbar-collapse" id="sidebar-menu">
{% nav %}
</div> </div>
{# Desktop Navigation #}
<div class="row search-container">
{# Empty spacer column to ensure search is centered. #}
<div class="col-3 d-flex flex-grow-1 ps-0"></div>
{# Search bar #}
<div class="col-6 d-flex flex-grow-1 justify-content-center">
{% include 'inc/searchbar.html' %}
</div> </div>
</aside>
{# Proflie/login button #} {# Top menu #}
<div class="col-3 d-flex flex-grow-1 pe-0 justify-content-end"> <header class="navbar navbar-expand-md d-none d-lg-flex d-print-none">
<div class="container-xl">
{# Toggle button #}
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu" aria-controls="navbar-menu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-nav flex-row order-md-last">
<div class="d-none d-md-flex">
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip" data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" /></svg>
</a>
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip" data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" /><path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" /></svg>
</a>
<div class="nav-item dropdown d-none d-md-flex me-3">
<a href="#" class="nav-link px-0" data-bs-toggle="dropdown" tabindex="-1" aria-label="Show notifications">
<!-- Download SVG icon from http://tabler-icons.io/i/bell -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6" /><path d="M9 17v1a3 3 0 0 0 6 0v-1" /></svg>
<span class="badge bg-red"></span>
</a>
<div class="dropdown-menu dropdown-menu-arrow dropdown-menu-end dropdown-menu-card">
<div class="card">
<div class="card-header">
<h3 class="card-title">Last updates</h3>
</div>
<div class="list-group list-group-flush list-group-hoverable">
<div class="list-group-item">
Item 1
</div>
<div class="list-group-item">
Item 2
</div>
<div class="list-group-item">
Item 3
</div>
<div class="list-group-item">
Item 4
</div>
</div>
</div>
</div>
</div>
</div>
{# User menu #}
{% include 'inc/profile_button.html' %} {% include 'inc/profile_button.html' %}
</div> </div>
{# Search box #}
<div class="collapse navbar-collapse" id="navbar-menu">
<form action="{% url 'search' %}" method="get" autocomplete="off" novalidate>
<div class="input-icon">
<span class="input-icon-addon">
<!-- Download SVG icon from http://tabler-icons.io/i/search -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" />
<path d="M21 21l-6 -6" />
</svg>
</span>
<input type="text" value="" class="form-control" placeholder="Search…" aria-label="Search NetBox">
</div>
</form>
</div> </div>
</nav> </div>
</header>
{# Page content #}
<div class="page-wrapper">
{# Page header #}
<div class="page-header d-print-none">
<div class="container-xl">
{% if config.BANNER_TOP %} {% if config.BANNER_TOP %}
<div class="text-center mx-3"> <div class="text-center mx-3">
@ -85,7 +138,6 @@ Blocks:
</div> </div>
{% endif %} {% endif %}
{# Page header #}
{% block header %} {% block header %}
<div class="title-container px-3 pb-3"> <div class="title-container px-3 pb-3">
@ -101,9 +153,13 @@ Blocks:
</div> </div>
{% endblock header %} {% endblock header %}
</div>
</div>
{# /Page header #}
{# Page content #} {# Page body #}
<div id="content" class="container-fluid content px-0 m-0"> <div class="page-body">
<div class="container-xl">
{% block tabs %}{% endblock %} {% block tabs %}{% endblock %}
{% block content-wrapper %} {% block content-wrapper %}
<div class="px-3"> <div class="px-3">
@ -117,64 +173,81 @@ Blocks:
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div>
{# /Page body #}
{# Page footer #}
<footer class="footer footer-transparent d-print-none">
<div class="container-xl">
{% block footer %}
<div class="row text-center align-items-center flex-row-reverse">
<div class="col-lg-auto ms-lg-auto">
<ul class="list-inline list-inline-dots mb-0">
{% block footer_links %}
{# Documentation #}
<li class="list-inline-item">
<a href="{% static 'docs/' %}" target="_blank" class="link-secondary" rel="noopener">
<i title="{% trans "Docs" %}" class="mdi mdi-book-open-variant text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
</li>
{# REST API #}
<li class="list-inline-item">
<a href="{% url 'api-root' %}" target="_blank" class="link-secondary" rel="noopener">
<i title="{% trans "REST API" %}" class="mdi mdi-cloud-braces text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
</li>
{# API docs #}
<li class="list-inline-item">
<a href="{% url 'api_docs' %}" target="_blank" class="link-secondary" rel="noopener">
<i title="{% trans "REST API documentation" %}" class="mdi mdi-book text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
</li>
{# GraphQL API #}
{% if config.GRAPHQL_ENABLED %}
<li class="list-inline-item">
<a href="{% url 'graphql' %}" target="_blank" class="link-secondary" rel="noopener">
<i title="{% trans "GraphQL API" %}" class="mdi mdi-graphql text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
</li>
{% endif %}
{# GitHub #}
<li class="list-inline-item">
<a href="https://github.com/netbox-community/netbox" target="_blank" class="link-secondary" rel="noopener">
<i title="{% trans "Source Code" %}" class="mdi mdi-github text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
</li>
{# NetDev Slack #}
<li class="list-inline-item">
<a href="https://netdev.chat" target="_blank" class="link-secondary" rel="noopener">
<i title="{% trans "Community" %}" class="mdi mdi-slack text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
</li>
{% endblock footer_links %}
</ul>
</div>
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item">
{% annotated_now %} {% now 'T' %}
</li>
<li class="list-inline-item">
<a href="./changelog.html" class="link-secondary" rel="noopener">
{{ settings.HOSTNAME }} (v{{ settings.VERSION }})
</a>
</li>
</ul>
</div>
</div>
{% endblock footer %}
</div>
</footer>
{# /Page footer #}
{# /Page content #}
</div>
{# BS5 pop-up modals #} {# BS5 pop-up modals #}
{% block modals %}{% endblock %} {% block modals %}{% endblock %}
{# Page footer #}
<footer class="footer container-fluid">
{% block footer %}
<div class="row align-items-center justify-content-between mx-0">
<div class="col-sm-12 col-md-auto fs-4 noprint">
<nav class="nav justify-content-center justify-content-lg-start">
{% block footer_links %}
{# Documentation #}
<a type="button" class="nav-link" href="{% static 'docs/' %}" target="_blank">
<i title="{% trans "Docs" %}" class="mdi mdi-book-open-variant text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
{# REST API #}
<a type="button" class="nav-link" href="{% url 'api-root' %}" target="_blank">
<i title="{% trans "REST API" %}" class="mdi mdi-cloud-braces text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
{# API docs #}
<a type="button" class="nav-link" href="{% url 'api_docs' %}" target="_blank">
<i title="{% trans "REST API documentation" %}" class="mdi mdi-book text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
{# GraphQL API #}
{% if config.GRAPHQL_ENABLED %}
<a type="button" class="nav-link" href="{% url 'graphql' %}" target="_blank">
<i title="{% trans "GraphQL API" %}" class="mdi mdi-graphql text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
{% endif %}
{# GitHub #}
<a type="button" class="nav-link" href="https://github.com/netbox-community/netbox" target="_blank">
<i title="{% trans "Source Code" %}" class="mdi mdi-github text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
{# NetDev Slack #}
<a type="button" class="nav-link" href="https://netdev.chat/" target="_blank">
<i title="{% trans "Community" %}" class="mdi mdi-slack text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
</a>
{% endblock footer_links %}
</nav>
</div>
<div class="col-sm-12 col-md-auto text-center text-lg-end text-muted">
<span class="d-block d-md-inline">{% annotated_now %} {% now 'T' %}</span>
<span class="ms-md-3 d-block d-md-inline">{{ settings.HOSTNAME }} (v{{ settings.VERSION }})</span>
</div>
</div>
{% endblock footer %}
</footer>
</div>
</main>
</div> </div>
{% endblock layout %} {% endblock layout %}

View File

@ -1,44 +0,0 @@
{% load navigation %}
{% load static %}
{% load i18n %}
<nav class="sidenav noprint" id="sidenav" data-simplebar>
<div class="sidenav-header">
{# Brand #}
{# Full Logo #}
<a class="sidenav-brand" href="{% url 'home' %}">
<img src="{% static 'netbox_logo.svg' %}" height="48" class="sidenav-brand-img" alt="{% trans "NetBox Logo" %}">
</a>
{# Icon Logo #}
<a class="sidenav-brand-icon" href="{% url 'home' %}">
<img src="{% static 'netbox_icon.svg' %}" height="32" class="sidenav-brand-img" alt="{% trans "NetBox Logo" %}">
</a>
{# Pin/Unpin Toggle #}
<button class="btn btn-sm btn-ghost-primary sidenav-toggle">
<div class="sidenav-toggle-icon">
<i class="mdi mdi-pin"></i>
</div>
</button>
</div>
<div class="sidenav-inner h-100 mb-auto">
{# Collapse #}
<div class="collapse sidenav-collapse pb-4">
{# Nav Items #}
{% nav %}
</div>
{# Profile controls #}
<div class="profile-button-container">
{% include 'inc/profile_button.html' %}
</div>
</div>
</nav>

View File

@ -1,67 +1,42 @@
{% load i18n %} {% load i18n %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="dropdown profile-button"> <div class="nav-item dropdown">
<button type="button" aria-expanded="false" data-bs-toggle="dropdown" class="btn btn-outline-secondary dropdown-toggle w-100"> <a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown" aria-label="Open user menu">
<i class="mdi mdi-account"></i> <span class="avatar avatar-sm"></span>
<span id="navbar_user">{{ request.user|truncatechars:"30" }}</span> <div class="d-none d-xl-block ps-2">
</button> <div>{{ request.user }}</div>
<ul class="dropdown-menu dropdown-menu-end"> <div class="mt-1 small text-secondary">{% if request.user.is_staff %}Staff{% else %}User{% endif %}</div>
<li> </div>
<button type="button" class="dropdown-item color-mode-toggle"> </a>
<i class="color-mode-icon mdi mdi-lightbulb"></i> <div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
<span class="color-mode-text">{% trans "Dark Mode" %}</span>
</button>
</li>
<li>
{% if request.user.is_staff %} {% if request.user.is_staff %}
<a class="dropdown-item" href="{% url 'admin:index' %}"> <a class="dropdown-item" href="{% url 'admin:index' %}">
<i class="mdi mdi-cog"></i> {% trans "Admin" %} <i class="mdi mdi-cog"></i> {% trans "Admin" %}
</a> </a>
{% endif %} {% endif %}
</li> <a href="{% url 'account:profile' %}" class="dropdown-item">
<li>
<a class="dropdown-item" href="{% url 'account:profile' %}">
<i class="mdi mdi-account"></i> {% trans "Profile" %} <i class="mdi mdi-account"></i> {% trans "Profile" %}
</a> </a>
</li> <a href="{% url 'account:bookmarks' %}" class="dropdown-item">
<li>
<a class="dropdown-item" href="{% url 'account:bookmarks' %}">
<i class="mdi mdi-bookmark"></i> {% trans "Bookmarks" %} <i class="mdi mdi-bookmark"></i> {% trans "Bookmarks" %}
</a> </a>
</li> <a href="{% url 'account:preferences' %}" class="dropdown-item">
<li>
<a class="dropdown-item" href="{% url 'account:preferences' %}">
<i class="mdi mdi-wrench"></i> {% trans "Preferences" %} <i class="mdi mdi-wrench"></i> {% trans "Preferences" %}
</a> </a>
</li> <a href="{% url 'account:usertoken_list' %}" class="dropdown-item">
<li>
<a class="dropdown-item" href="{% url 'account:usertoken_list' %}">
<i class="mdi mdi-key"></i> {% trans "API Tokens" %} <i class="mdi mdi-key"></i> {% trans "API Tokens" %}
</a> </a>
</li> <div class="dropdown-divider"></div>
<li><hr class="dropdown-divider" /></li> <a href="{% url 'logout' %}" class="dropdown-item">
<li>
<a class="dropdown-item" href="{% url 'logout' %}">
<i class="mdi mdi-logout-variant"></i> {% trans "Log Out" %} <i class="mdi mdi-logout-variant"></i> {% trans "Log Out" %}
</a> </a>
</li> </div>
</ul>
</div> </div>
{% else %} {% else %}
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-primary ws-nowrap" type="button" href="{% url 'login' %}?next={{ request.path }}"> <a class="btn btn-primary ws-nowrap" type="button" href="{% url 'login' %}?next={{ request.path }}">
<i class="mdi mdi-login-variant"></i> {% trans "Log In" %} <i class="mdi mdi-login-variant"></i> {% trans "Log In" %}
</a> </a>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
<span class="visually-hidden">{% trans "Toggle Dropdown" %}</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button class="dropdown-item color-mode-toggle">
<i class="color-mode-icon mdi mdi-lightbulb"></i>
<span class="color-mode-text">{% trans "Dark Mode" %}</span>
</button>
</li>
</ul>
</div> </div>
{% endif %} {% endif %}

View File

@ -1,6 +0,0 @@
<form class="input-group" action="{% url 'search' %}" method="get">
<input name="q" type="text" aria-label="Search" placeholder="Search" class="form-control" />
<button class="btn btn-primary" type="submit">
<i class="mdi mdi-magnify"></i>
</button>
</form>

View File

@ -1,43 +1,37 @@
{% load helpers %} {% load helpers %}
<ul class="navbar-nav"> <ul class="navbar-nav pt-lg-3">
{% for menu, groups in nav_items %} {% for menu, groups in nav_items %}
<li class="nav-item"> <li class="nav-item dropdown">
{# Menu heading #} {# Menu heading #}
<a class="nav-link" href="#menu{{ menu.name }}" data-bs-toggle="collapse" role="button" aria-expanded="false" aria-controls="menu{{ menu.name }}"> <a class="nav-link dropdown-toggle" href="#navbar-base" data-bs-toggle="dropdown" data-bs-auto-close="false" role="button" aria-expanded="false" >
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="{{ menu.icon_class }}"></i> <i class="{{ menu.icon_class }}"></i>
<span class="nav-link-text">{{ menu.label }}</span> </span>
<span class="nav-link-title">
{{ menu.label }}
</span>
</a> </a>
{# Menu groups #} {# Menu groups #}
<div class="collapse" id="menu{{ menu.name }}"> <div class="dropdown-menu">
<ul class="nav nav-sm flex-column"> <div class="dropdown-menu-columns">
<div class="dropdown-menu-column">
{% for group, items in groups %} {% for group, items in groups %}
{# Group heading #} <div class="hr-text dropdown-item m-0 ps-2">
<li class="nav-item"> <span>{{ group.label }}</span>
<div class="nav-group-header">
<span class="nav-group-label">{{ group.label }}</span>
</div> </div>
</li>
{# Group items #}
{% for item, buttons in items %} {% for item, buttons in items %}
<li class="nav-item{% if not item.buttons %} no-buttons{% endif %}"> <a class="dropdown-item ps-2" href="{% url item.link %}">
{# Item #} {{ item.link_text }}
<a href="{% url item.link %}" class="nav-link">{{ item.link_text }}</a>
{# Item buttons (if any) #}
{% if buttons %}
<div class="btn-group px-2">
{% for button in buttons %}
<a class="btn btn-sm btn-{{ button.color }} lh-1" href="{% url button.link %}" title="{{ button.title }}">
<i class="{{ button.icon_class }}"></i>
</a> </a>
{% endfor %} {% endfor %}
</div>
{% endif %}
</li>
{% endfor %} {% endfor %}
{% endfor %}
</ul>
</div> </div>
</div>
</div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>