moved 'in-app menu' from the sidebar to the top of the content; some template block renaming

This commit is contained in:
fonfon 2014-11-26 10:50:32 +01:00 committed by Sunil Mohan Adapa
parent e4c11e7d8e
commit 96a14e3d0d
38 changed files with 266 additions and 239 deletions

View File

@ -40,13 +40,12 @@ the title field.
### Layout
Plinth expects a `main` block. This is where the meat of the content
goes. It is the center pain in the default layout. There is a
`title` block that the program will fill with text describing the
current page. `sidebar_left` contains the submenu navigation menu,
and `sidebar_right` is where we put all short text that helps the
admin fill out forms. They don't have to be sidebars, and they don't
have to go on the left and right.
Plinth expects a `content` block. This is where the meat of the
content goes. It is the center pane in the default layout. There
is a `title` block that the program will fill with text describing
the current page. There are two bars on the left side: `submenu`
for the menu and `sidebar` where short help texts go.
The lowest layer in the navigation is `subsubmenu`, displayed on top
of the content pane.
It is possible to override the `footer`, but I haven't yet found a
reason to do so.
All these items are inside of blocks and can be overwritten.

View File

@ -144,6 +144,7 @@ def configure_django():
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.request',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',

View File

@ -18,8 +18,9 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<h2>Apps</h2>
<p>User Applications are web apps hosted on your
{{ cfg.product_name }}.</p>

View File

@ -20,7 +20,7 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
{% if is_expert %}

View File

@ -18,7 +18,8 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<h2>{{ title }}</h2>
<p>The system diagnostic test will run a number of checks on your
system to confirm that network services are running and configured

View File

@ -18,7 +18,7 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
{% if diagnostics_error %}
<p>The diagnostic test encountered an error:<p>

View File

@ -28,13 +28,14 @@ from plinth.modules.lib.auth import get_or_create_group
class ExpertsForm(forms.Form): # pylint: disable-msg=W0232
"""Form to configure expert mode"""
expert_mode = forms.BooleanField(
label=_('Expert Mode'), required=False)
label=_('Enable Expert Mode'), required=False)
def init():
"""Initialize the module"""
menu = cfg.main_menu.get('system:index')
menu.add_urlname(_('Expert Mode'), 'glyphicon-wrench', 'expert_mode:index', 10)
menu.add_urlname(_('Expert Mode'), 'glyphicon-wrench',
'expert_mode:index', 10)
@login_required
@ -70,7 +71,7 @@ def _apply_changes(request, new_status):
expert_group = get_or_create_group('Expert')
if new_status['expert_mode']:
if not expert_group in request.user.groups.all():
if expert_group not in request.user.groups.all():
request.user.groups.add(expert_group)
message = (messages.success, _('Expert mode enabled'))
else:

View File

@ -20,7 +20,9 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<h2>{{ title }}</h2>
<p>The {{ cfg.box_name }} can be administered in two modes, 'basic'
and 'expert'. Basic mode hides a lot of features and configuration

View File

@ -18,7 +18,8 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<h2>{{ title }}</h2>
<p>Firewall is a network security system that controls the incoming
and outgoing network traffic on your {{ cfg.box_name }}. Keeping a

View File

@ -17,7 +17,7 @@
#
{% endcomment %}
<div class="well sidebar-nav">
<div class="well sidebar">
<h3>Getting Help</h3>

View File

@ -25,7 +25,7 @@
<link rel="stylesheet" href="{% static 'first_boot/state0.css' %}"/>
{% endblock %}
{% block main_block %}
{% block content %}
<h2>Welcome to Your FreedomBox!</h2>
@ -42,7 +42,7 @@
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
{% include "firstboot_sidebar.html" %}
{% endblock %}

View File

@ -20,7 +20,7 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
{% if user.is_authenticated %}
<p>Have fun with your {{ cfg.box_name }}!</p>
@ -30,7 +30,7 @@
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
{% include "firstboot_sidebar.html" %}

View File

@ -33,13 +33,6 @@ class State0View(CreateView):
form_class = State0Form
success_url = reverse_lazy('first_boot:state10')
def get_context_data(self, **kwargs):
"""Set 'sidebar_right' to display the sidebar_right in the templates.
Otherwise we wouldn't be able to include firstboot_sidebar.html"""
context = super(State0View, self).get_context_data(**kwargs)
context['sidebar_right'] = "a"
return context
def get_initial(self):
initial = super(State0View, self).get_initial()
initial['hostname'] = config.get_hostname()
@ -62,6 +55,5 @@ def state10(request):
kvstore.set('firstboot_state', 10)
return render_to_response('firstboot_state10.html',
{'title': _('Setup Complete'),
'sidebar_right': 'a'},
{'title': _('Setup Complete')},
context_instance=RequestContext(request))

View File

@ -40,14 +40,14 @@ def init():
def index(request):
"""Serve the index page"""
return TemplateResponse(request, 'help.html',
return TemplateResponse(request, 'help_index.html',
{'title': _('Documentation and FAQ')})
def about(request):
"""Serve the about page"""
title = _('About the {box_name}').format(box_name=cfg.box_name)
return TemplateResponse(request, 'about.html', {'title': title})
return TemplateResponse(request, 'help_about.html', {'title': title})
def helppage(request, page):
@ -55,10 +55,10 @@ def helppage(request, page):
try:
with open(os.path.join(cfg.doc_dir, '%s.part.html' % page), 'r') \
as input_file:
main = input_file.read()
content = input_file.read()
except IOError:
raise Http404
title = _('%s Documentation') % cfg.product_name
return TemplateResponse(request, 'base.html',
{'title': title, 'main': main})
return TemplateResponse(request, 'help_detail.html',
{'title': title, 'content': content})

View File

@ -19,7 +19,7 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<img src="{% static 'theme/img/freedombox-logo-250px.png' %}"
class="main-graphic" />
@ -38,16 +38,15 @@ runs on must be cheap. The software it runs on must be easy to
install and administrate by anybody. It must be easy to
transition from existing services.</p>
<p>
<a class="btn btn-primary btn-lg" href="http://wiki.debian.org/FreedomBox"
target="_blank">Learn more&raquo;</a>
</p>
<p><a class="btn btn-primary btn-lg"
href="http://wiki.debian.org/FreedomBox" target="_blank">Learn more
&raquo;</a></p>
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
<div class="well sidebar-nav">
<div class="well sidebar">
<h3>Our Goal</h3>

View File

@ -1,3 +1,4 @@
{% extends 'base.html' %}
{% comment %}
#
# This file is part of Plinth.
@ -17,11 +18,7 @@
#
{% endcomment %}
<ul class='nav nav-list'>
<li class='nav-header'>{{ menu.title }}</li>
{% for item in menu.items %}
<li>
<a href="{{ item.url }}">{{ item.text }}</a>
</li>
{% endfor %}
</ul>
{% block content %}
{{ content|safe }}
{% endblock %}

View File

@ -18,8 +18,9 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<h2>Help</h2>
<p>There are a variety of places to go for help with
{{ cfg.product_name }} and the box it runs on.</p>

View File

@ -20,13 +20,12 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<form class="form" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<h2>OwnCloud</h2>
<p>When enabled, the owncloud installation will be available
from <a href="/owncloud">owncloud</a> on the web server. Visit
this URL to set up the initial administration account for
@ -36,15 +35,16 @@
5 minutes or more, depending on download bandwidth from the
Debian APT sources.</strong></p>
<input type="submit" class="btn btn-primary" value="Update setup"/>
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary btn-md" value="Update setup"/>
</form>
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
<div class="well sidebar-nav">
<div class="well sidebar">
<h3>ownCloud</h3>

View File

@ -20,7 +20,8 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<h2>{{ title }}</h2>
<p>aptitude purge modules</p>
@ -44,9 +45,9 @@
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
<div class="well sidebar-nav">
<div class="well sidebar">
<h3>Help</h3>

View File

@ -24,8 +24,6 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core import validators
from django.core.urlresolvers import reverse_lazy
from django.template import RequestContext
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
from gettext import gettext as _
import logging
@ -36,27 +34,26 @@ from plinth import cfg
LOGGER = logging.getLogger(__name__)
subsubmenu = {'title': _('PageKite'),
'items': [{'url': reverse_lazy('pagekite:index'),
'text': _('About PageKite')},
{'url': reverse_lazy('pagekite:configure'),
'text': _('Configure PageKite')}]}
def init():
"""Intialize the PageKite module"""
menu = cfg.main_menu.get('apps:index')
menu.add_urlname(_('Public Visibility (PageKite)'), 'glyphicon-globe',
'pagekite:index', 50)
menu.add_urlname(_('Public Visibility (PageKite)'),
'glyphicon-flag', 'pagekite:index', 50)
@login_required
def index(request):
"""Serve introdution page"""
menu = {'title': _('PageKite'),
'items': [{'url': reverse_lazy('pagekite:configure'),
'text': _('Configure PageKite')}]}
sidebar_right = render_to_string('menu_block.html', {'menu': menu},
RequestContext(request))
"""Serve introduction page"""
return TemplateResponse(request, 'pagekite_introduction.html',
{'title': _('Public Visibility (PageKite)'),
'sidebar_right': sidebar_right})
'subsubmenu': subsubmenu})
class TrimmedCharField(forms.CharField):
@ -123,7 +120,8 @@ def configure(request):
return TemplateResponse(request, 'pagekite_configure.html',
{'title': _('Configure PageKite'),
'form': form})
'form': form,
'subsubmenu': subsubmenu})
def get_status():

View File

@ -20,7 +20,7 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
{% if pagekite_status = 'not_installed' %}

View File

@ -18,7 +18,8 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<p>PageKite is a system for exposing {{ cfg.box_name }} services when
you don't have a direct connection to the Internet. You only need this
service if your {{ cfg.box_name }} services are unreachable from the

View File

@ -18,7 +18,9 @@
#
{% endcomment %}
{% block main_block %}
{% block content %}
<h2>System</h2>
<p>In this section, you can control the {{ cfg.product_name }}'s
underlying system, as opposed to its various applications and

View File

@ -20,7 +20,7 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
{% if is_installed %}
@ -42,12 +42,12 @@ Here is the current configuration:</p>
<li>Ports: {{ tor_hs_ports }}</li>
</ul>
<form class="form" method="post">
<form class="form form-inline" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary" value="Update setup"/>
<input type="submit" class="btn btn-primary btn-sm" value="Update setup"/>
</form>
<h3>Bridge</h3>
@ -56,15 +56,17 @@ can help circumvent censorship. If your {{ cfg.box_name }} is behind a router
or firewall, you should make sure the following ports are open, and
port-forwarded, if necessary:</p>
<div class="col-sm-3">
<table class="table table-bordered table-condensed">
{% for name, port in tor_ports.items %}
<tr>
<td>{{ name }}</td>
<td>{{ port }}</td>
</tr>
{% endfor %}
</table>
<div class="row">
<div class="col-sm-3">
<table class="table table-bordered table-condensed">
{% for name, port in tor_ports.items %}
<tr>
<td>{{ name }}</td>
<td>{{ port }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
<br style='clear:both'>
@ -84,9 +86,9 @@ port-forwarded, if necessary:</p>
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
<div class="well sidebar-nav">
<div class="well sidebar">
<h3>Tor</h3>

View File

@ -20,7 +20,7 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<form class="form" method="post">
{% csrf_token %}
@ -33,9 +33,9 @@
{% endblock %}
{% block sidebar_right_block %}
{% block sidebar %}
<div class="well sidebar-nav">
<div class="well sidebar">
<h3>Add User</h3>

View File

@ -20,7 +20,13 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<h3>Delete Users</h3>
Currently you can not edit but only delete users from {{ cfg.product_name }}
and the {{ cfg.box_name }} system.
<p>Deleting users is permanent!</p>
<form class="form" method="post">
{% csrf_token %}
@ -32,19 +38,3 @@
</form>
{% endblock %}
{% block sidebar_right_block %}
<div class="well sidebar-nav">
<h3>Delete Users</h3>
<p>Check the box next to a users' names and then click "Delete
User" to remove users from {{ cfg.product_name }} and the
{{ cfg.box_name }} system.</p>
<p>Deleting users is permanent!</p>
</div>
{% endblock %}

View File

@ -20,11 +20,15 @@ URLs for the Users module
"""
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
urlpatterns = patterns( # pylint: disable-msg=C0103
'plinth.modules.users.users',
url(r'^sys/users/$', 'index', name='index'),
# create an index page (that only forwards) to have correct highlighting
# of submenu items
url(r'^sys/users/$', RedirectView.as_view(pattern_name='users:add'),
name='index'),
url(r'^sys/users/add/$', 'add', name='add'),
url(r'^sys/users/edit/$', 'edit', name='edit')
url(r'^sys/users/edit/$', 'edit', name='edit'),
)

View File

@ -21,8 +21,6 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core import validators
from django.core.urlresolvers import reverse_lazy
from django.template import RequestContext
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
from gettext import gettext as _
import logging
@ -34,27 +32,18 @@ from plinth.modules.lib.auth import add_user
LOGGER = logging.getLogger(__name__)
subsubmenu = {'title': _('Users and Groups'),
'items': [{'url': reverse_lazy('users:add'),
'text': _('Add User')},
{'url': reverse_lazy('users:edit'),
'text': _('Edit Users')}]}
def init():
"""Intialize the module"""
menu = cfg.main_menu.get('system:index')
menu.add_urlname(_('Users and Groups'), 'glyphicon-user', 'users:index', 15)
@login_required
def index(request):
"""Return a rendered users page"""
menu = {'title': _('Users and Groups'),
'items': [{'url': reverse_lazy('users:add'),
'text': _('Add User')},
{'url': reverse_lazy('users:edit'),
'text': _('Edit Users')}]}
sidebar_right = render_to_string('menu_block.html', {'menu': menu},
RequestContext(request))
return TemplateResponse(request, 'base.html',
{'title': _('Manage Users and Groups'),
'sidebar_right': sidebar_right})
menu.add_urlname(_('Users and Groups'), 'glyphicon-user', 'users:index',
15)
class UserAddForm(forms.Form): # pylint: disable-msg=W0232
@ -90,7 +79,8 @@ def add(request):
return TemplateResponse(request, 'users_add.html',
{'title': _('Add User'),
'form': form})
'form': form,
'subsubmenu': subsubmenu})
def _add_user(request, data):
@ -134,8 +124,9 @@ def edit(request):
form = UserEditForm(prefix='user')
return TemplateResponse(request, 'users_edit.html',
{'title': _('Delete Users'),
'form': form})
{'title': _('Edit or Delete User'),
'form': form,
'subsubmenu': subsubmenu})
def _apply_edit_changes(request, data):

View File

@ -20,16 +20,28 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<p>XMPP Server Accounts and Configuration</p>
{% if is_installed %}
{% if not is_installed %}
<p>XMPP is an open and standardized communication protocol.
Here you can run and configure your XMPP server, called ejabberd.
To actually communicate you can use the
<a href='/jwchat'>web client</a>
or any other
<a href='http://xmpp.org/xmpp-software/clients/' target='_blank'>
XMPP client
</a>.</p>
<a href='/jwchat' target='_blank'class='btn btn-primary'>
Launch web client
</a>
<p>ejabberd is not installed, please install it. ejabberd comes pre-installed
with {{ cfg.box_name }}. On any Debian-based system (such as
{% else %}
<h2>XMPP Server</h2>
<p>The XMPP server <i>ejabberd</i> is not installed.<br />ejabberd comes
pre-installed with {{ cfg.box_name }}. On any Debian-based system (such as
{{ cfg.box_name }}) you may install it using the command
'aptitude install ejabberd'.</p>
<code>aptitude install ejabberd</code>.</p>
{% endif %}

View File

@ -20,14 +20,14 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<form class="form" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary" value="Update setup"/>
<input type="submit" class="btn btn-primary btn-md" value="Update setup"/>
</form>

View File

@ -20,16 +20,24 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<form class="form" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary"
value="Register XMPP Account"/>
<div class='row'>
<div class='col-sm-4'>
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary" value="Register XMPP Account"/>
</div>
</div>
</form>
{% endblock %}
{% block page_js %}
<script>
$('#id_xmpp-username').focus();
</script>
{% endblock %}

View File

@ -19,8 +19,6 @@ from django import forms
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse_lazy
from django.template import RequestContext
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
from gettext import gettext as _
import logging
@ -32,9 +30,13 @@ from plinth import service
LOGGER = logging.getLogger(__name__)
SIDE_MENU = {
subsubmenu = {
'title': _('XMPP'),
'items': [
{
'url': reverse_lazy('xmpp:index'),
'text': _('About'),
},
{
'url': reverse_lazy('xmpp:configure'),
'text': _('Configure XMPP Server'),
@ -50,7 +52,6 @@ SIDE_MENU = {
def init():
"""Initialize the XMPP module"""
menu = cfg.main_menu.get('apps:index')
menu.add_item('Chat', 'glyphicon-comment', '/../jwchat', 20)
menu.add_urlname('XMPP', 'glyphicon-comment', 'xmpp:index', 40)
service.Service(
@ -72,15 +73,14 @@ def index(request):
['get-installed']).strip() == 'installed'
if is_installed:
sidebar_right = render_to_string('menu_block.html', {'menu': SIDE_MENU},
RequestContext(request))
index_subsubmenu = subsubmenu
else:
sidebar_right = None
index_subsubmenu = None
return TemplateResponse(request, 'xmpp.html',
{'title': _('XMPP Server'),
'is_installed': is_installed,
'sidebar_right': sidebar_right})
'subsubmenu': index_subsubmenu})
class ConfigureForm(forms.Form): # pylint: disable-msg=W0232
@ -108,13 +108,10 @@ def configure(request):
else:
form = ConfigureForm(initial=status, prefix='xmpp')
sidebar_right = render_to_string('menu_block.html', {'menu': SIDE_MENU},
RequestContext(request))
return TemplateResponse(request, 'xmpp_configure.html',
{'title': _('Configure XMPP Server'),
'form': form,
'sidebar_right': sidebar_right})
'subsubmenu': subsubmenu})
def get_status():
@ -171,13 +168,10 @@ def register(request):
else:
form = RegisterForm(prefix='xmpp')
sidebar_right = render_to_string('menu_block.html', {'menu': SIDE_MENU},
RequestContext(request))
return TemplateResponse(request, 'xmpp_register.html',
{'title': _('Register XMPP Account'),
'form': form,
'sidebar_right': sidebar_right})
'subsubmenu': subsubmenu})
def _register_user(request, data):

View File

@ -18,11 +18,8 @@
#
{% endcomment %}
{% block title_block %}
404
{% endblock %}
{% block main_block %}
{% block content %}
<h2>404</h2>
<p>Requested page {{ request_path }} was not found.</p>

View File

@ -18,11 +18,8 @@
#
{% endcomment %}
{% block title_block %}
500
{% endblock %}
{% block main_block %}
{% block content %}
<h2>500</h2>
<p>This is an internal error and not something you caused or can fix. Please
report the error on

View File

@ -25,43 +25,48 @@
<!--[if gt IE 9]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<!-- the "no-js" class is for Modernizr -->
<head>
<meta charset="utf-8" />
<meta charset="utf-8" />
<!-- Always force latest IE rendering engine and Chrome Frame -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<!-- Always force latest IE rendering engine and Chrome Frame -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<!-- Mobile Viewport Fix http://j.mp/mobileviewport & http://davidbcalhoun.com/2010/viewport-metatag
device-width : Occupy full width of the screen in its current orientation
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
maximum-scale = 1.0 retains dimensions instead of zooming in if page width < device width
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Mobile Viewport Fix http://j.mp/mobileviewport & http://davidbcalhoun.com/2010/viewport-metatag
device-width : Occupy full width of the screen in its current orientation
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
maximum-scale = 1.0 retains dimensions instead of zooming in if page width < device width
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- R2D2, you know better than to trust a strange computer! -->
<meta name="robots" content="noindex, nofollow, noarchive" />
<meta name="googlebot" content="noindex, nofollow, noarchive, nosnippet, noodp, noimageindex, notranslate" />
<meta name="msnbot" content="noindex, nofollow, noarchive, noodp" />
<meta name="slurp" content="noindex, nofollow, noarchive, noodp, noydir" />
<meta name="description" content="Plinth administrative interface for the FreedomBox" />
<title>{% if title %} {{ title }} {% else %} FreedomBox {% endif %}</title>
<!-- R2D2, you know better than to trust a strange computer! -->
<meta name="robots" content="noindex, nofollow, noarchive" />
<meta name="googlebot" content="noindex, nofollow, noarchive, nosnippet, noodp, noimageindex, notranslate" />
<meta name="msnbot" content="noindex, nofollow, noarchive, noodp" />
<meta name="slurp" content="noindex, nofollow, noarchive, noodp, noydir" />
<meta name="description" content="Plinth administrative interface for the FreedomBox" />
{% block title %}
<title>
{% if title %} {{ title }} {% else %} FreedomBox {% endif %}
</title>
{% endblock %}
<!-- This is the traditional favicon. Size: 16x16 or 32x32, transparency is OK -->
<link rel="shortcut icon" href="{% static 'theme/img/favicon.ico' %}"/>
<!-- This is the traditional favicon. Size: 16x16 or 32x32, transparency is OK -->
<link rel="shortcut icon" href="{% static 'theme/img/favicon.ico' %}"/>
<!-- The is the icon for iOS's Web Clip. Size: 57x57 for older iPhones, 72x72 for iPads, 114x114 for iPhone4
- To prevent iOS from applying its styles to the icon name it thusly: apple-touch-icon-precomposed.png
- Transparency is not recommended (iOS will put a black BG behind the icon) -->
<link rel="apple-touch-icon" sizes="57x57" href="{% static 'theme/img/apple-touch-icon-57px-precomposed.png' %}"/>
<link rel="apple-touch-icon" sizes="72x72" href="{% static 'theme/img/apple-touch-icon-72px-precomposed.png' %}"/>
<link rel="apple-touch-icon" sizes="114x114" href="{% static 'theme/img/apple-touch-icon-114px-precomposed.png' %}"/>
<!-- The is the icon for iOS's Web Clip. Size: 57x57 for older iPhones, 72x72 for iPads, 114x114 for iPhone4
- To prevent iOS from applying its styles to the icon name it thusly: apple-touch-icon-precomposed.png
- Transparency is not recommended (iOS will put a black BG behind the icon) -->
<link rel="apple-touch-icon" sizes="57x57" href="{% static 'theme/img/apple-touch-icon-57px-precomposed.png' %}"/>
<link rel="apple-touch-icon" sizes="72x72" href="{% static 'theme/img/apple-touch-icon-72px-precomposed.png' %}"/>
<link rel="apple-touch-icon" sizes="114x114" href="{% static 'theme/img/apple-touch-icon-114px-precomposed.png' %}"/>
<!-- Bootstrap base CSS -->
<link rel="stylesheet" href="{% static 'theme/bootstrap/css/bootstrap.min.css' %}"/>
<link rel="stylesheet" href="{% static 'theme/css/plinth.css' %}"/>
<!-- Bootstrap base CSS -->
<link rel="stylesheet" href="{% static 'theme/bootstrap/css/bootstrap.min.css' %}"/>
<link rel="stylesheet" href="{% static 'theme/css/plinth.css' %}"/>
{% block app_head %}<!-- placeholder for app/module-specific head files -->{% endblock %}
{% block page_head %}<!-- placeholder for page-specific head files -->{% endblock %}
</head>
<body>
<!--[if lt IE 7]><p class=chromeframe>Your browser is <em>ancient!</em> <a href="http://mozilla.org/firefox">Upgrade to a modern version of Firefox</a> to experience this site.</p><![endif]-->
<div class="navbar navbar-fixed-top navbar-inverse" role="navigation">
@ -121,39 +126,41 @@
<div class="container-fluid">
<div class="row">
{% if submenu or sidebar_right or sidebar_left %}
<div class="col-md-3">
{% if submenu %}
<div class="well sidebar-nav">
{% include "menu.html" with menu=submenu %}
</div><!--/.well -->
{% endif %}
{% if sidebar_left %}
<div class="well sidebar-nav">
{{ sidebar_left|safe }}
</div><!--/.well -->
{% endif %}
{% block sidebar_right_block %}
{% if sidebar_right %}
<div class="well sidebar-nav">
{{ sidebar_right|safe }}
<div class="col-md-3">
{% block submenu %}
{% if submenu %}
<div class="well sidebar">
{% include "submenu.html" with menu=submenu %}
</div><!--/.well -->
{% endif %}
{% endblock %}
</div>
{% endif %}
{% block sidebar %}
{# this sidebar should contain help texts but no menus #}
{% endblock %}
</div>
<div class="col-md-9">
<div class="well">
<h2>
{% block title_block %}
{{ title }}
{% endblock %}
</h2>
{% block subsubmenu %}
{% if subsubmenu %}
<ul class="nav nav-tabs">
{% for urlitem in subsubmenu.items %}
<li {% if urlitem.url == request.path %} class="active"{% endif %}
role="presentation">
<a href="{{ urlitem.url }}">{{ urlitem.text }}</a>
</li>
{% endfor %}
</ul>
<br />
{% endif %}
{% endblock %}
{% include 'messages.html' %}
{% block main_block %}
{{ main|safe }}
{% block content %}
{# main content goes here #}
{% endblock %}
</div>
</div><!--/col-->

View File

@ -20,7 +20,7 @@
{% load bootstrap %}
{% block main_block %}
{% block content %}
<form class="form" method="post">

View File

@ -0,0 +1,37 @@
{% comment %}
#
# This file is part of Plinth.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
{% endcomment %}
<ul class="nav nav-pills nav-stacked">
{% for item in menu.items %}
{% if item.url in active_menu_urls %}
<li class="active">
<a href="{{ item.url }}" class="active">
<span class="{{ item.icon }} glyphicon"></span>
{% else %}
<li>
<a href="{{ item.url }}">
<span class="{{ item.icon }} glyphicon"></span>
{% endif %}
{{ item.label }}
</a>
</li>
{% endfor %}
</ul>

View File

@ -2,15 +2,6 @@ body {
padding-top: 70px;
}
/* nav-header is deprecated in bootstrap 3.x, so replicate it here */
.nav-header {
text-transform: uppercase;
font-weight: bold;
font-size: 11px;
display: block;
color: #999;
}
.nav .glyphicon,
.sidebar .glyphicon {
margin-right: 4px;