Skip to content

Commit 820c718

Browse files
committed
move navbar to side
1 parent a33fc59 commit 820c718

5 files changed

Lines changed: 115 additions & 74 deletions

File tree

patchman/static/css/base.css

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
.panel-body { padding: 5px; font-size: 12px; }
66
.panel { margin-bottom: 5px; font-size: 12px; }
77
.panel-heading { padding: 5px; font-size: 13px; }
8-
.breadcrumb { font-size: 12px; background-color: #222; border-radius: 0; margin-bottom: 3px; }
8+
.breadcrumb { font-size: 14px; background-color: #222; border-radius: 0; margin-bottom: 3px; position: sticky; top: 0; z-index: 100; }
99
.navbar { margin-bottom: 0; padding-bottom: 0; border-radius: 0; }
1010
.navbar-inverse .dropdown-menu { background-color: #222; }
1111
.navbar-inverse .dropdown-menu > li > a { color: #9d9d9d; }
@@ -24,6 +24,24 @@ td.truncate-cell a { display: block; overflow: hidden; text-overflow: ellipsis;
2424
.expandable-text { cursor: pointer; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2525
.expandable-text.expanded { white-space: normal; overflow: visible; }
2626

27+
/* Sidebar layout */
28+
.sidebar-layout { display: flex; min-height: 100vh; }
29+
.sidebar-nav { width: 200px; background-color: #222; display: flex; flex-direction: column; position: fixed; height: 100vh; }
30+
.sidebar-header { padding: 15px; border-bottom: 1px solid #333; }
31+
.sidebar-brand { color: #9d9d9d; font-size: 18px; font-weight: bold; text-decoration: none; }
32+
.sidebar-brand:hover { color: #fff; text-decoration: none; }
33+
.sidebar-menu { list-style: none; padding: 0; margin: 0; }
34+
.sidebar-menu li a { display: block; padding: 10px 15px; color: #9d9d9d; text-decoration: none; font-size: 14px; }
35+
.sidebar-menu li a:hover { background-color: #333; color: #fff; }
36+
.sidebar-menu li.active > a { background-color: #333; color: #fff; }
37+
.sidebar-menu .submenu { list-style: none; padding: 0; margin: 0; display: none; background-color: #1a1a1a; }
38+
.sidebar-menu .submenu li a { padding-left: 30px; font-size: 13px; }
39+
.sidebar-menu .has-submenu.open > .submenu { display: block; }
40+
.sidebar-menu .has-submenu > a .caret { float: right; margin-top: 6px; transition: transform 0.2s; }
41+
.sidebar-menu .has-submenu.open > a .caret { transform: rotate(180deg); }
42+
.sidebar-bottom { margin-top: auto; border-top: 1px solid #333; }
43+
.main-content { margin-left: 200px; flex: 1; }
44+
2745
/* Center pagination controls produced by django-tables2 without centering table cell contents */
2846
.django-tables2 .pagination {
2947
text-align: center;

patchman/static/js/expandable-text.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,36 @@ document.addEventListener('DOMContentLoaded', function() {
55
this.classList.toggle('expanded');
66
});
77
});
8+
9+
// Sidebar submenu state from localStorage
10+
const STORAGE_KEY = 'patchman_sidebar_state';
11+
const savedState = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
12+
13+
// Apply saved state to submenus
14+
const submenuItems = document.querySelectorAll('.has-submenu');
15+
submenuItems.forEach((item, index) => {
16+
const menuId = item.querySelector('a').textContent.trim();
17+
if (savedState[menuId] !== undefined) {
18+
if (savedState[menuId]) {
19+
item.classList.add('open');
20+
} else {
21+
item.classList.remove('open');
22+
}
23+
}
24+
});
25+
26+
// Toggle submenu and save state
27+
const submenuLinks = document.querySelectorAll('.has-submenu > a');
28+
submenuLinks.forEach(link => {
29+
link.addEventListener('click', function(e) {
30+
e.preventDefault();
31+
const parent = this.parentElement;
32+
parent.classList.toggle('open');
33+
// Save state to localStorage
34+
const menuId = this.textContent.trim();
35+
const currentState = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
36+
currentState[menuId] = parent.classList.contains('open');
37+
localStorage.setItem(STORAGE_KEY, JSON.stringify(currentState));
38+
});
39+
});
840
});

util/templates/base.html

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,21 @@
1212
{% block extrahead %}{% endblock %}
1313
</head>
1414
<body>
15-
<div>
15+
<div class="sidebar-layout">
1616
{% include "navbar.html" with user=user %}
17-
<ul class="breadcrumb">
18-
{% block breadcrumbs %}
19-
<li class="active"><a href="{% url 'util:dashboard' %}">Home</a></li>
20-
{% endblock %}
21-
</ul>
22-
{% bootstrap_messages %}
23-
<div class="well well-sm">
24-
<div class="panel panel-default">
25-
<div class="panel-heading">
26-
<strong>{% block content_title %}{% endblock %}</strong>
17+
<div class="main-content">
18+
<ul class="breadcrumb">
19+
{% block breadcrumbs %}
20+
{% endblock %}
21+
</ul>
22+
{% bootstrap_messages %}
23+
<div class="well well-sm">
24+
<div class="panel panel-default">
25+
<div class="panel-body">
26+
{% block content %}{{ content }}{% endblock %}
27+
</div>
28+
{% block footer %}{% endblock %}
2729
</div>
28-
<div class="panel-body">
29-
{% block content %}{{ content }}{% endblock %}
30-
</div>
31-
{% block footer %}{% endblock %}
3230
</div>
3331
</div>
3432
</div>

util/templates/dashboard.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
{% block page_title %}Patchman Dashboard{% endblock %}
66

7+
{% block breadcrumbs %}
8+
<li class="active"><a href="{% url 'util:dashboard' %}">Issues</a></li>
9+
{% endblock %}
10+
711
{% block content_title %} Issues Dashboard for {{ site.name }} {% endblock %}
812

913
{% block content %}

util/templates/navbar.html

Lines changed: 47 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,50 @@
1-
<nav class="navbar navbar-inverse">
2-
<div class="container-fluid">
3-
<div class="navbar-header">
4-
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
5-
<span class="icon-bar"></span>
6-
<span class="icon-bar"></span>
7-
<span class="icon-bar"></span>
8-
</button>
9-
<a class="navbar-brand" href="https://github.com/furlongm/patchman">Patchman</a>
10-
</div>
11-
<div class="collapse navbar-collapse" id="myNavbar">
12-
<ul class="nav navbar-nav">
13-
<li class="{% if '/hosts' in request.path %}active{% endif %}"> <a href="{% url 'hosts:host_list' %}">Hosts</a></li>
14-
<li class="dropdown {% if '/repos' in request.path or '/mirrors' in request.path %}active{% endif %}">
15-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Repositories <span class="caret"></span></a>
16-
<ul class="dropdown-menu">
17-
<li><a href="{% url 'repos:repo_list' %}">Repositories</a></li>
18-
<li><a href="{% url 'repos:mirror_list' %}">Mirrors</a></li>
19-
</ul>
20-
</li>
21-
<li class="{% if '/packages' in request.path %}active{% endif %}"> <a href="{% url 'packages:package_name_list' %}">Packages</a></li>
22-
<li class="{% if '/errata' in request.path %}active{% endif %}"> <a href="{% url 'errata:erratum_list' %}">Errata</a></li>
23-
<li class="dropdown {% if '/cves' in request.path or '/cwes' in request.path or '/references' in request.path or '/security' in request.path %}active{% endif %}">
24-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Security <span class="caret"></span></a>
25-
<ul class="dropdown-menu">
26-
<li><a href="{% url 'security:cve_list' %}">CVEs</a></li>
27-
<li><a href="{% url 'security:cwe_list' %}">CWEs</a></li>
28-
<li><a href="{% url 'errata:erratum_list' %}?e_type=security">Security Errata</a></li>
29-
<li><a href="{% url 'security:reference_list' %}">Security References</a></li>
30-
</ul>
31-
</li>
32-
<li class="dropdown {% if '/os' in request.path %}active{% endif %}">
33-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Operating Systems <span class="caret"></span></a>
34-
<ul class="dropdown-menu">
35-
<li><a href="{% url 'operatingsystems:osrelease_list' %}">OS Releases</a></li>
36-
<li><a href="{% url 'operatingsystems:osvariant_list' %}">OS Variants</a></li>
37-
</ul>
38-
</li>
39-
<li class="{% if '/reports' in request.path %}active{% endif %}"> <a href="{% url 'reports:report_list' %}">Reports</a></li>
40-
<li class="{% if '/dashboard' in request.path %}active{% endif %}"><a href="{% url 'util:dashboard' %}">Issues{% if issues_count %} <span class="badge">{{ issues_count }}</span>{% endif %}</a></li>
1+
<nav class="sidebar-nav">
2+
<div class="sidebar-header">
3+
<a class="sidebar-brand" href="https://github.com/furlongm/patchman">Patchman</a>
4+
</div>
5+
<ul class="sidebar-menu">
6+
<li class="{% if '/hosts' in request.path %}active{% endif %}"><a href="{% url 'hosts:host_list' %}">Hosts</a></li>
7+
<li class="has-submenu open {% if '/repos' in request.path or '/mirrors' in request.path %}active{% endif %}">
8+
<a href="#">Repositories <span class="caret"></span></a>
9+
<ul class="submenu">
10+
<li><a href="{% url 'repos:repo_list' %}">Repositories</a></li>
11+
<li><a href="{% url 'repos:mirror_list' %}">Mirrors</a></li>
4112
</ul>
42-
<ul class="nav navbar-nav navbar-right">
43-
{% if user.is_authenticated %}
44-
<li class="dropdown">
45-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
46-
{% if user.first_name %}{{ user.first_name }}{% else %}{{ user }}{% endif %} <span class="caret"></span>
47-
</a>
48-
<ul class="dropdown-menu">
49-
{% if user.is_superuser %}
50-
<li><a href="{% url 'admin:index' %}">Django Admin</a></li>
51-
{% endif %}
52-
<li><a href="{% url 'logout' %}">Log out</a></li>
53-
</ul>
54-
</li>
55-
{% else %}
56-
<li><a href="{% url 'login' %}">Log In</a></li>
57-
{% endif %}
13+
</li>
14+
<li class="{% if '/packages' in request.path %}active{% endif %}"><a href="{% url 'packages:package_name_list' %}">Packages</a></li>
15+
<li class="{% if '/errata' in request.path %}active{% endif %}"><a href="{% url 'errata:erratum_list' %}">Errata</a></li>
16+
<li class="has-submenu open {% if '/cves' in request.path or '/cwes' in request.path or '/references' in request.path or '/security' in request.path %}active{% endif %}">
17+
<a href="#">Security <span class="caret"></span></a>
18+
<ul class="submenu">
19+
<li><a href="{% url 'security:cve_list' %}">CVEs</a></li>
20+
<li><a href="{% url 'security:cwe_list' %}">CWEs</a></li>
21+
<li><a href="{% url 'errata:erratum_list' %}?e_type=security">Security Errata</a></li>
22+
<li><a href="{% url 'security:reference_list' %}">Security References</a></li>
5823
</ul>
59-
</div>
60-
</div>
24+
</li>
25+
<li class="has-submenu open {% if '/os' in request.path %}active{% endif %}">
26+
<a href="#">Operating Systems <span class="caret"></span></a>
27+
<ul class="submenu">
28+
<li><a href="{% url 'operatingsystems:osrelease_list' %}">OS Releases</a></li>
29+
<li><a href="{% url 'operatingsystems:osvariant_list' %}">OS Variants</a></li>
30+
</ul>
31+
</li>
32+
<li class="{% if '/reports' in request.path %}active{% endif %}"><a href="{% url 'reports:report_list' %}">Reports</a></li>
33+
<li class="{% if '/dashboard' in request.path %}active{% endif %}"><a href="{% url 'util:dashboard' %}">Issues{% if issues_count %} <span class="badge">{{ issues_count }}</span>{% endif %}</a></li>
34+
</ul>
35+
<ul class="sidebar-menu sidebar-bottom">
36+
{% if user.is_authenticated %}
37+
<li class="has-submenu open">
38+
<a href="#">Logged in as {% if user.first_name %}{{ user.first_name }}{% else %}{{ user }}{% endif %} <span class="caret"></span></a>
39+
<ul class="submenu">
40+
{% if user.is_superuser %}
41+
<li><a href="{% url 'admin:index' %}">Django Admin</a></li>
42+
{% endif %}
43+
<li><a href="{% url 'logout' %}">Log out</a></li>
44+
</ul>
45+
</li>
46+
{% else %}
47+
<li><a href="{% url 'login' %}">Log In</a></li>
48+
{% endif %}
49+
</ul>
6150
</nav>

0 commit comments

Comments
 (0)