Arrange navbar items by functions

This commit is contained in:
Brice Maron 2019-07-29 22:10:58 +02:00 committed by Alexis Metaireau
parent b5cc1592d6
commit fd49599cc7
9 changed files with 95 additions and 41 deletions

View file

@ -8,3 +8,4 @@ ACTIVATE_DEMO_PROJECT = True
ADMIN_PASSWORD = ""
ALLOW_PUBLIC_PROJECT_CREATION = True
ACTIVATE_ADMIN_DASHBOARD = False
SUPPORTED_LANGUAGES = ['en', 'fr', 'nl']

View file

@ -10,7 +10,8 @@ from werkzeug.contrib.fixers import ProxyFix
from ihatemoney.api import api
from ihatemoney.models import db
from ihatemoney.utils import PrefixedWSGI, minimal_round, IhmJSONEncoder
from ihatemoney.utils import (IhmJSONEncoder, PrefixedWSGI, locale_from_iso,
minimal_round, static_include)
from ihatemoney.web import main as web_interface
from ihatemoney import default_settings
@ -135,6 +136,8 @@ def create_app(configuration=None, instance_path='/etc/ihatemoney',
app.mail = mail
# Jinja filters
app.jinja_env.globals['static_include'] = static_include
app.jinja_env.globals['locale_from_iso'] = locale_from_iso
app.jinja_env.filters['minimal_round'] = minimal_round
# Translations
@ -144,7 +147,10 @@ def create_app(configuration=None, instance_path='/etc/ihatemoney',
def get_locale():
# get the lang from the session if defined, fallback on the browser "accept
# languages" header.
lang = session.get('lang', request.accept_languages.best_match(['fr', 'en']))
lang = session.get(
'lang',
request.accept_languages.best_match(app.config['SUPPORTED_LANGUAGES'])
)
setattr(g, 'lang', lang)
return lang

View file

@ -328,3 +328,16 @@ tr:hover .extra-info {
.row-fluid > .offset1 {
margin-left: 8.5%;
}
.globe-europe svg {
display: inline-block;
border-bottom: 0.2em solid transparent;
height: 1.2em;
fill: rgba(255,255,255,.5)
}
.navbar-nav .dropdown-toggle:hover .globe-europe svg {
fill: rgba(255,255,255,.75);
}
.navbar-dark .navbar-nav .show > .nav-link svg {
fill: white;
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm200 248c0 22.5-3.9 44.2-10.8 64.4h-20.3c-4.3 0-8.4-1.7-11.4-4.8l-32-32.6c-4.5-4.6-4.5-12.1.1-16.7l12.5-12.5v-8.7c0-3-1.2-5.9-3.3-8l-9.4-9.4c-2.1-2.1-5-3.3-8-3.3h-16c-6.2 0-11.3-5.1-11.3-11.3 0-3 1.2-5.9 3.3-8l9.4-9.4c2.1-2.1 5-3.3 8-3.3h32c6.2 0 11.3-5.1 11.3-11.3v-9.4c0-6.2-5.1-11.3-11.3-11.3h-36.7c-8.8 0-16 7.2-16 16v4.5c0 6.9-4.4 13-10.9 15.2l-31.6 10.5c-3.3 1.1-5.5 4.1-5.5 7.6v2.2c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8s-3.6-8-8-8H247c-3 0-5.8 1.7-7.2 4.4l-9.4 18.7c-2.7 5.4-8.2 8.8-14.3 8.8H194c-8.8 0-16-7.2-16-16V199c0-4.2 1.7-8.3 4.7-11.3l20.1-20.1c4.6-4.6 7.2-10.9 7.2-17.5 0-3.4 2.2-6.5 5.5-7.6l40-13.3c1.7-.6 3.2-1.5 4.4-2.7l26.8-26.8c2.1-2.1 3.3-5 3.3-8 0-6.2-5.1-11.3-11.3-11.3H258l-16 16v8c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8v-20c0-2.5 1.2-4.9 3.2-6.4l28.9-21.7c1.9-.1 3.8-.3 5.7-.3C358.3 56 448 145.7 448 256zM130.1 149.1c0-3 1.2-5.9 3.3-8l25.4-25.4c2.1-2.1 5-3.3 8-3.3 6.2 0 11.3 5.1 11.3 11.3v16c0 3-1.2 5.9-3.3 8l-9.4 9.4c-2.1 2.1-5 3.3-8 3.3h-16c-6.2 0-11.3-5.1-11.3-11.3zm128 306.4v-7.1c0-8.8-7.2-16-16-16h-20.2c-10.8 0-26.7-5.3-35.4-11.8l-22.2-16.7c-11.5-8.6-18.2-22.1-18.2-36.4v-23.9c0-16 8.4-30.8 22.1-39l42.9-25.7c7.1-4.2 15.2-6.5 23.4-6.5h31.2c10.9 0 21.4 3.9 29.6 10.9l43.2 37.1h18.3c8.5 0 16.6 3.4 22.6 9.4l17.3 17.3c3.4 3.4 8.1 5.3 12.9 5.3H423c-32.4 58.9-93.8 99.5-164.9 103.1z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -28,55 +28,71 @@
</head>
<body>
<div class="container">
<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark">
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggler" aria-controls="navbarToggler" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<h1><a class="navbar-brand" href="{{ url_for("main.home") }}">#! money?</a></h1>
{% if g.project %}<strong class="d-block d-sm-none text-white">{{ g.project.name }}</strong>{% endif %}
<div class="collapse navbar-collapse" id="navbarToggler">
<ul class="navbar-nav ml-auto mr-auto">
{% if g.project %}
<li class="nav-item">
</li>
{% block navbar %}
<li class="nav-item{% if current_view == 'list_bills' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.list_bills") }}">{{ _("Bills") }}</a></li>
<li class="nav-item{% if current_view == 'settle_bill' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.settle_bill") }}">{{ _("Settle") }}</a></li>
<li class="nav-item{% if current_view == 'statistics' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.statistics") }}">{{ _("Statistics") }}</a></li>
{% endblock %}
{% endif %}
{% if g.project %}
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<strong class="d-none d-sm-inline">{{ g.project.name }}</strong> {{ _("options") }}
<a href="#" class="nav-link dropdown-toggle" id="navbarProjectsLinks" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<strong class="text-white">{{ g.project.name }}</strong>
<b class="caret"></b>
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="{{ url_for("main.edit_project") }}">{{ _("Project settings") }}</a></li>
<ul class="dropdown-menu" aria-labelledby="navbarProjectsLinks">
<li><a class="dropdown-item" href="{{ url_for("main.create_project") }}">{{ _("Start a new project") }}</a></li>
{% if (session['projects'] | length) > 1 %}
<li class="dropdown-divider"></li>
<li class="dropdown-header">{{ _('Other projects :') }}</li>
{% for id, name in session['projects'] %}
{% if id != g.project.id %}
<li><a class="dropdown-item" href="{{ url_for("main.list_bills", project_id=id) }}">{{ _("switch to") }} {{ name }}</a></li>
{% endif %}
{% endfor %}
<li><a class="dropdown-item" href="{{ url_for("main.create_project") }}">{{ _("Start a new project") }}</a></li>
{% if g.show_admin_dashboard_link %}
<li class="dropdown-divider"></li>
<li class="nav-item{% if request.url_rule.endpoint == "main.dashboard" %} active{% endif %}">
<a class="dropdown-item" href="{{ url_for("main.dashboard") }}">{{ _("Dashboard") }}</a>
</li>
{% endif %}
<li class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ url_for("main.exit") }}">{{ _("Logout") }}</a></li>
</ul>
</li>
{% endif %}
</ul>
<ul class="navbar-nav secondary-nav">
<li class="nav-item{% if g.lang == "fr" %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.change_lang", lang="fr") }}">fr</a></li>
<li class="nav-item{% if g.lang == "en" %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.change_lang", lang="en") }}">en</a></li>
</li>
</ul>
{% endif %}
<div class="collapse navbar-collapse" id="navbarToggler">
<ul class="navbar-nav ml-auto mr-auto">
{% if g.project %}
{% block navbar %}
<li class="nav-item{% if current_view == 'list_bills' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.list_bills") }}">{{ _("Bills") }}</a></li>
<li class="nav-item{% if current_view == 'settle_bill' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.settle_bill") }}">{{ _("Settle") }}</a></li>
<li class="nav-item{% if current_view == 'statistics' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.statistics") }}">{{ _("Statistics") }}</a></li>
<li class="nav-item{% if current_view == 'edit_project' %} active{% endif %}""><a class="nav-link" href="{{ url_for("main.edit_project") }}">{{ _("Settings") }}</a></li>
{% endblock %}
{% endif %}
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="langMenuButton">
<i class="globe-europe">{{ static_include("images/globe.svg") | safe }}</i>
{% if g.lang %}
{{ locale_from_iso(g.lang).display_name | capitalize }}
{% else %}
{{ _('Languages') }}
{% endif %}
<b class="caret"></b>
</a>
<div class="dropdown-menu" aria-labelledby="langMenuButton">
<h6 class="dropdown-header">{{ _('Languages') }}</h6>
{% for lang in config['SUPPORTED_LANGUAGES'] %}
{% if g.lang != lang %}
<a class="dropdown-item" href="{{ url_for("main.change_lang", lang=lang)}}">{{ locale_from_iso(lang).display_name | capitalize }}</a>
{% endif %}
{% endfor %}
</div>
</li>
{% if (session['projects'] | length) > 0 or session['is_admin'] %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for("main.exit") }}">{{ _("Logout") }}</a>
</li>
{% endif %}
</ul>
</div>
</nav>

View file

@ -1,13 +1,15 @@
from __future__ import division
import base64
import re
import os
import ast
import operator
from io import BytesIO, StringIO
import jinja2
from json import dumps, JSONEncoder
from flask import redirect
from flask import redirect, current_app
from babel import Locale
from werkzeug.routing import HTTPException, RoutingException
import six
from datetime import datetime, timedelta
@ -93,6 +95,16 @@ def minimal_round(*args, **kw):
return (res if res != ires else ires)
def static_include(filename):
fullpath = os.path.join(current_app.static_folder, filename)
with open(fullpath, 'r') as f:
return f.read()
def locale_from_iso(iso_code):
return Locale(iso_code)
def list_of_dicts2json(dict_to_convert):
"""Take a list of dictionnaries and turns it into
a json in-memory file

View file

@ -343,7 +343,12 @@ def edit_project():
edit_form.name.data = g.project.name
edit_form.contact_email.data = g.project.contact_email
return render_template("edit_project.html", edit_form=edit_form, export_form=export_form)
return render_template(
"edit_project.html",
edit_form=edit_form,
export_form=export_form,
current_view="edit_project"
)
@main.route("/<project_id>/delete")