Add new sidebar main menu

Add a left side menu navigation style. The main app navigation links
will be displayed here. The notification, user and system tools are now
displayed at the top navigation bar.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2018-12-20 16:42:50 -04:00
parent f77f64cc71
commit 60ac63ead4
12 changed files with 276 additions and 40 deletions

View File

@@ -202,6 +202,11 @@
- Updated the source test behavior to allow testing a source
even when the source is disabled and to not deleted downloaded
content during a test.
- Update the user interface to add new sidebar main menu for a
more common left side menu navigation style. The main app
navigation links will be displayed here. The notification,
user and system tools are now displayed at the top navigation
bar.
3.1.9 (2018-11-01)
==================

View File

@@ -49,10 +49,6 @@
url('../fonts/Lato_400italic.ttf') format('truetype');
}
body {
padding-top: 70px;
}
.navbar-brand {
font-family: "IM Fell English SC", serif;
}
@@ -142,11 +138,7 @@ hr {
}
.radio ul li {
list-style-type:none;
}
a i {
padding-right: 3px;
list-style-type: none;
}
.dashboard-widget {
@@ -341,3 +333,148 @@ a i {
font-size: 110%;
font-weight: bold;
}
body {
padding-top: 40px;
}
.sub-header {
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
/*
* Top navigation
* Hide default border to remove 1px line.
*/
.navbar-fixed-top {
border: 0;
}
/*
* Sidebar
*/
/* Hide for mobile, show later */
.sidebar {
display: none;
}
@media (min-width: 768px) {
.sidebar {
position: fixed;
top: 51px;
bottom: 0;
left: 0;
z-index: 1000;
display: block;
padding-top: 10px;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
background-color: #2c3e50;
border-right: 1px solid #18bc9c;
}
.navbar-brand {
text-align: center;
width: 210px;
}
}
/*
* Main content
*/
.main {
padding: 20px;
}
@media (min-width: 768px) {
.main {
padding-right: 0px;
padding-left: 0px;
margin-left: 210px;
}
}
.main .page-header {
margin-top: 0;
}
.sidebar {
width: 210px;
}
.navbar-brand {
}
.container-fluid {
margin-right: 0px;
margin-left: 0px;
width: 100%;
}
.navbar-form > .form-control {
padding: 0px;
height: 35px;
margin-top: 3px;
}
#accordion-sidebar a {
padding: 10px 15px;
}
#accordion-sidebar a[aria-expanded="true"] {
background: #1a242f;
}
#accordion-sidebar .panel {
border: 0px;
}
#accordion-sidebar a {
text-decoration: none;
outline: none;
position: relative;
display: block;
}
#accordion-sidebar .panel-heading {
background-color: #2c3e50;
color: white;
padding: 0px;
}
#accordion-sidebar .panel-heading:hover {
background-color: #517394;
}
#accordion-sidebar .panel-title {
font-size: 15px;
}
#accordion-sidebar .panel-body {
font-size: 13px;
border: 0px;
background-color: #2c3e50;
padding-top: 5px;
padding-left: 20px;
padding-right: 0px;
padding-bottom: 0px;
}
#accordion-sidebar .panel-body li {
padding: 0px;
}
#accordion-sidebar .panel-body li:hover {
background-color: #517394;
}
#accordion-sidebar .panel-body a {
color: white;
text-decoration: none;
padding: 9px;
}
.navbar-brand {
outline: none;
}

View File

@@ -4,18 +4,13 @@ class MayanApp {
constructor (parameters) {
var self = this;
parameters = parameters || {}
parameters = parameters || {
ajaxMenusOptions: []
}
this.ajaxSpinnerSeletor = '#ajax-spinner';
this.ajaxExecuting = false;
this.ajaxMenusOptions = [
{
app: this,
interval: 5000,
menuSelector: '#main-menu',
url: apiTemplateMainMenuURL,
}
];
this.ajaxMenusOptions = parameters.ajaxMenusOptions;
this.ajaxMenuHashes = {};
this.window = $(window);
}
@@ -214,6 +209,8 @@ class MayanApp {
}
initialize () {
var self = this;
this.setupAJAXPeriodicWorkers();
this.setupAJAXSpinner();
this.setupAutoSubmit();
@@ -223,6 +220,7 @@ class MayanApp {
this.setupNavbarCollapse();
this.setupNewWindowAnchor();
$.each(this.ajaxMenusOptions, function(index, value) {
value.app = self;
app.doRefreshAJAXMenu(value);
});
partialNavigation.initialize();

View File

@@ -1 +1 @@
<i class="fa {{ css_classes }}"></i>
<i class="fa {{ css_classes }}" style="padding-right: 5px; width: auto;"></i>

View File

@@ -1 +1 @@
<i class="fa fa-{{ symbol }}"></i>
<i class="fa fa-{{ symbol }}" style="padding-right: 5px; width: auto;"></i>

View File

@@ -15,8 +15,8 @@
<a class="navbar-brand" href="{% url home_view %}">{% smart_setting 'COMMON_PROJECT_TITLE' %}</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
{% get_menu_links 'main menu' as menu_links %}
<ul class="nav navbar-nav navbar-right">
{% get_menu_links 'menu topbar' as menu_links %}
{% for link_set in menu_links %}
{% for link in link_set %}
{% with 'true' as as_li %}

View File

@@ -0,0 +1,70 @@
{% load i18n %}
{% load navigation_tags %}
{% load smart_settings_tags %}
{% load common_tags %}
{% load navigation_tags %}
<div class="panel-group" id="accordion-sidebar" role="tablist" aria-multiselectable="true">
{% get_menu_links 'main menu' as menu_links %}
{% for link_set in menu_links %}
{% for link in link_set %}
{% with 'true' as as_li %}
{% with 'true' as hide_active_anchor %}
{% with 'active' as li_class_active %}
{% with 'first' as li_class_first %}
{% with ' ' as link_classes %}
{% if link|get_type == "<class 'mayan.apps.navigation.classes.Menu'>" %}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a class="non-ajax collapsed" role="button" data-toggle="collapse" data-parent="#accordion-sidebar" href="#accordion-body-{{ forloop.counter }}" aria-expanded="false" aria-controls="collapseOne">
<div class="pull-left">
{% if link.icon %}
<i class="hidden-xs hidden-sm hidden-md {{ link.icon }}"></i>
{% endif %}
{% if link.icon_class %}{{ link.icon_class.render }}{% endif %}
{{ link.label }}
</div>
<div class="accordion-indicator pull-right"><span class="caret"></span></div>
<div class="clearfix"></div>
</a>
</h4>
</div>
<div id="accordion-body-{{ forloop.counter }}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
<ul class="list-unstyled">
{% get_menu_links link.name as menu_links %}
{% for linkset in menu_links %}
{% with '' as li_class_active %}
{% with linkset as object_navigation_links %}
{% include 'navigation/generic_navigation.html' %}
{% endwith %}
{% endwith %}
{% endfor %}
</ul>
</div>
</div>
</div>
{% else %}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
{% include 'navigation/generic_link_instance.html' %}
</h4>
</div>
</div>
{% endif %}
{% endwith %}
{% endwith %}
{% endwith %}
{% endwith %}
{% endwith %}
{% endfor %}
{% endfor %}
</div>

View File

@@ -33,13 +33,18 @@
{% if appearance_type == 'plain' %}
{% block content_plain %}{% endblock %}
{% else %}
<div id="main-menu">
{% include 'appearance/main_menu.html' %}
<div id="menu-main">
{% include 'appearance/menu_main.html' %}
</div>
<div class="container-fluid">
<div class="row">
<div class="col-xs-12">
<div id="ajax-content"></div>
<div class="sidebar" id="menu-sidebar">
{% include 'appearance/menu_sidebar.html' %}
</div>
<div class="main">
<div class="row">
<div class="col-xs-12">
<div id="ajax-content"></div>
</div>
</div>
</div>
</div>
@@ -102,11 +107,26 @@
{# Transfer variable from Django to javascript #}
var initialURL = '{% url home_view %}';
var djangoDEBUG = {% if debug %}true{% else %}false{% endif %};
var apiTemplateMainMenuURL = '{% url "rest_api:template-detail" "main_menu" %}';
var apiTemplateMainMenuURL = '{% url "rest_api:template-detail" "menu_main" %}';
</script>
<script src="{% static 'appearance/js/base.js' %}" type="text/javascript"></script>
<script>
var app = new MayanApp();
var app = new MayanApp({
ajaxMenusOptions: [
{
interval: 5000,
menuSelector: '#menu-sidebar',
name: 'menu_main',
url: '{% url "rest_api:template-detail" "menu_sidebar" %}'
},
{
interval: 5000,
menuSelector: '#menu-main',
name: 'menu_sidebar',
url: '{% url "rest_api:template-detail" "menu_main" %}'
},
]
});
var afterBaseLoad = function () {
MayanImage.intialize({

View File

@@ -31,7 +31,9 @@ from .links import (
link_setup, link_tools, separator_user_label, text_user_label
)
from .literals import DELETE_STALE_UPLOADS_INTERVAL, MESSAGE_SQLITE_WARNING
from .menus import menu_about, menu_main, menu_secondary, menu_user
from .menus import (
menu_about, menu_secondary, menu_topbar, menu_user
)
from .queues import * # NOQA - Force queues registration
from .settings import (
setting_auto_logging, setting_production_error_log_path,
@@ -90,7 +92,10 @@ class CommonApp(MayanAppConfig):
warnings.warn(force_text(MESSAGE_SQLITE_WARNING))
Template(
name='main_menu', template_name='appearance/main_menu.html'
name='menu_main', template_name='appearance/menu_main.html'
)
Template(
name='menu_sidebar', template_name='appearance/menu_sidebar.html'
)
app.conf.beat_schedule.update(
@@ -139,7 +144,7 @@ class CommonApp(MayanAppConfig):
)
)
menu_main.bind_links(links=(menu_about, menu_user,), position=99)
menu_topbar.bind_links(links=(menu_about, menu_user,), position=99)
menu_secondary.bind_links(
links=(link_object_error_list_clear,), sources=(
'common:object_error_list',

View File

@@ -9,7 +9,7 @@ from .icons import icon_menu_about, icon_menu_user
__all__ = (
'menu_about', 'menu_facet', 'menu_list_facet', 'menu_main', 'menu_object',
'menu_multi_item', 'menu_secondary', 'menu_setup', 'menu_sidebar',
'menu_tools', 'menu_user'
'menu_tools', 'menu_topbar', 'menu_user'
)
menu_about = Menu(
@@ -24,6 +24,7 @@ menu_secondary = Menu(name='secondary menu')
menu_setup = Menu(name='setup menu')
menu_sidebar = Menu(name='sidebar menu')
menu_tools = Menu(name='tools menu')
menu_topbar = Menu(name='menu topbar')
menu_user = Menu(
icon_class=icon_menu_user, name='user menu', label=_('User')
)

View File

@@ -18,7 +18,7 @@ class CommonAPITestCase(BaseAPITestCase):
@override_settings(LANGUAGE_CODE='de')
def test_template_detail_view(self):
self.login_user()
template_main_menu = Template.get(name='main_menu')
template_main_menu = Template.get(name='menu_main')
response = self.client.get(template_main_menu.get_absolute_url())
self.assertContains(
@@ -26,7 +26,7 @@ class CommonAPITestCase(BaseAPITestCase):
)
def test_template_detail_anonymous_view(self):
template_main_menu = Template.get(name='main_menu')
template_main_menu = Template.get(name='menu_main')
response = self.client.get(template_main_menu.get_absolute_url())
self.assertNotContains(
response=response, text=TEST_TEMPLATE_RESULT, status_code=403

View File

@@ -5,8 +5,8 @@ from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
from mayan.apps.common import (
MayanAppConfig, menu_list_facet, menu_main, menu_object, menu_secondary,
menu_tools, menu_user
MayanAppConfig, menu_list_facet, menu_object, menu_secondary,
menu_tools, menu_topbar, menu_user
)
from mayan.apps.common.widgets import TwoStateWidget
from mayan.apps.navigation import SourceColumn
@@ -86,9 +86,6 @@ class EventsApp(MayanAppConfig):
menu_list_facet.bind_links(
links=(link_user_events,), sources=(User,)
)
menu_main.bind_links(
links=(link_user_notifications_list,), position=99
)
menu_object.bind_links(
links=(link_notification_mark_read,), sources=(Notification,)
)
@@ -97,6 +94,9 @@ class EventsApp(MayanAppConfig):
sources=('events:user_notifications_list',)
)
menu_tools.bind_links(links=(link_events_list,))
menu_topbar.bind_links(
links=(link_user_notifications_list,), position=1
)
menu_user.bind_links(
links=(
link_event_types_subscriptions_list, link_current_user_events