multiple ui improvements

This commit is contained in:
envoyr
2022-03-14 18:18:35 +01:00
parent 31fbe434b4
commit 2c5c0258bf
52 changed files with 414 additions and 323 deletions

View File

@@ -59,7 +59,7 @@ class ProgressBar
private static function pbData(string $field, array $attributes, int $size_factor = 1024, int $report_max = 90, $infotext = null): array private static function pbData(string $field, array $attributes, int $size_factor = 1024, int $report_max = 90, $infotext = null): array
{ {
$percent = 0; $percent = 0;
$style = 'bg-info'; $style = 'bg-primary';
$text = PhpHelper::sizeReadable($attributes[$field . '_used'] * $size_factor, null, 'bi') . ' / ' . UI::getLng('panel.unlimited'); $text = PhpHelper::sizeReadable($attributes[$field . '_used'] * $size_factor, null, 'bi') . ' / ' . UI::getLng('panel.unlimited');
if ((int)$attributes[$field] >= 0) { if ((int)$attributes[$field] >= 0) {
if (($attributes[$field] / 100) * $report_max < $attributes[$field . '_used']) { if (($attributes[$field] / 100) * $report_max < $attributes[$field . '_used']) {

View File

@@ -28,7 +28,8 @@ class Listing
return [ return [
'title' => $tabellisting['title'], 'title' => $tabellisting['title'],
'icon' => $tabellisting['icon'], 'description' => $tabellisting['description'] ?? null,
'icon' => $tabellisting['icon'] ?? null,
'table' => [ 'table' => [
'th' => self::generateTableHeadings($tabellisting), 'th' => self::generateTableHeadings($tabellisting),
'tr' => self::generateTableRows($collection['data']['list'], $tabellisting), 'tr' => self::generateTableRows($collection['data']['list'], $tabellisting),

View File

@@ -84,7 +84,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'admins', 'section' => 'admins',
'page' => 'admins', 'page' => 'admins',

View File

@@ -25,6 +25,7 @@ use Froxlor\UI\Listing;
return [ return [
'customer_list' => [ 'customer_list' => [
'title' => $lng['admin']['customers'], 'title' => $lng['admin']['customers'],
'description' => 'Manage your customers',
'icon' => 'fa-solid fa-user', 'icon' => 'fa-solid fa-user',
'columns' => [ 'columns' => [
'c.name' => [ 'c.name' => [
@@ -91,7 +92,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'customers', 'section' => 'customers',
'page' => 'customers', 'page' => 'customers',

View File

@@ -101,7 +101,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'domains', 'section' => 'domains',
'page' => 'domains', 'page' => 'domains',

View File

@@ -44,7 +44,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'templates', 'section' => 'templates',
'page' => $page, 'page' => $page,

View File

@@ -66,7 +66,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'phpsettings', 'section' => 'phpsettings',
'page' => 'fpmdaemons', 'page' => 'fpmdaemons',

View File

@@ -98,7 +98,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'ipsandports', 'section' => 'ipsandports',
'page' => 'ipsandports', 'page' => 'ipsandports',

View File

@@ -50,7 +50,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'templates', 'section' => 'templates',
'page' => $page, 'page' => $page,

View File

@@ -71,7 +71,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'phpsettings', 'section' => 'phpsettings',
'page' => 'overview', 'page' => 'overview',

View File

@@ -62,7 +62,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'plans', 'section' => 'plans',
'page' => 'overview', 'page' => 'overview',

View File

@@ -69,7 +69,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'domains', 'section' => 'domains',
'page' => 'sslcertificates', 'page' => 'sslcertificates',

View File

@@ -105,7 +105,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'domains', 'section' => 'domains',
'page' => 'domains', 'page' => 'domains',

View File

@@ -73,7 +73,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'email', 'section' => 'email',
'page' => 'emails', 'page' => 'emails',

View File

@@ -64,7 +64,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'ftp', 'section' => 'ftp',
'page' => 'ftps', 'page' => 'ftps',

View File

@@ -76,7 +76,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'extras', 'section' => 'extras',
'page' => 'htaccess', 'page' => 'htaccess',

View File

@@ -52,7 +52,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'extras', 'section' => 'extras',
'page' => 'htpasswds', 'page' => 'htpasswds',

View File

@@ -65,7 +65,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'mysql', 'section' => 'mysql',
'page' => 'mysqls', 'page' => 'mysqls',

View File

@@ -71,7 +71,7 @@ return [
'delete' => [ 'delete' => [
'icon' => 'fa fa-trash', 'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'], 'title' => $lng['panel']['delete'],
'class' => 'text-danger', 'class' => 'btn-danger',
'href' => [ 'href' => [
'section' => 'index', 'section' => 'index',
'page' => 'apikeys', 'page' => 'apikeys',

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -25,16 +25,9 @@
{{ theme_js|raw }} {{ theme_js|raw }}
{% endif %} {% endif %}
{% block custom_js %}{% endblock %} {% block custom_js %}{% endblock %}
<title>Froxlor <title>Froxlor{% if page_title %} | {{ page_title }}{% endif %}</title>
{% if page_title %}
|
{{ page_title }}
{% endif %}
</title>
</head> </head>
<body {% if body_class is defined %}class="{{ body_class }}"{% endif %}> <body class="min-vh-100 d-flex flex-column">
{{ global_errors|raw }}
{% block navigation %}{% endblock %} {% block navigation %}{% endblock %}
{% block body %} {% block body %}

View File

@@ -1,4 +1,4 @@
<footer class="py-5 text-center"> <footer class="text-center mb-3">
<span> <span>
<img src="{{ basehref|default("") }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor"/> <img src="{{ basehref|default("") }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor"/>
{% if install_mode is not defined %} {% if install_mode is not defined %}

View File

@@ -3,15 +3,6 @@
{% import "Froxlor/form/formfields.html.twig" as formfields %} {% import "Froxlor/form/formfields.html.twig" as formfields %}
<form action="{{ formaction|default("") }}" method="post" enctype="application/x-www-form-urlencoded" class="form"> <form action="{{ formaction|default("") }}" method="post" enctype="application/x-www-form-urlencoded" class="form">
{% if title is not empty %}
<h3 class="page-header">
{% if form_data.image is not empty %}
<i class="{{ form_data.image }}"></i>
{% endif %}
{{ title }}
</h3>
{% endif %}
{% for section in form_data.sections %} {% for section in form_data.sections %}
<div class="card mb-3"> <div class="card mb-3">
{% if section.title is not empty %} {% if section.title is not empty %}
@@ -22,7 +13,7 @@
{{ section.title }} {{ section.title }}
</div> </div>
{% endif %} {% endif %}
<div class="card-body"> <div class="formfields">
{% for id,field in section.fields %} {% for id,field in section.fields %}
{{ formfields.fieldrow(id, field) }} {{ formfields.fieldrow(id, field) }}
{% endfor %} {% endfor %}
@@ -31,20 +22,18 @@
{% endfor %} {% endfor %}
<!-- submit buttons --> <!-- submit buttons -->
<div class="card mb-3"> <div>
<div class="card-body"> {% if hiddenid is not empty %}
{% if hiddenid is not empty %} <input type="hidden" name="id" value="{{ hiddenid }}"/>
<input type="hidden" name="id" value="{{ hiddenid }}"/> {% endif %}
{% endif %} <input type="hidden" name="s" value="{{ s }}"/>
<input type="hidden" name="s" value="{{ s }}"/> <input type="hidden" name="page" value="{{ page }}"/>
<input type="hidden" name="page" value="{{ page }}"/> <input type="hidden" name="action" value="{{ action }}"/>
<input type="hidden" name="action" value="{{ action }}"/> <input type="hidden" name="send" value="send"/>
<input type="hidden" name="send" value="send"/>
<div class="col-12 text-center"> <div class="col-12 text-end">
<button type="reset" class="btn btn-warning">{{ lng('panel.cancel') }}</button> <button type="reset" class="btn btn-outline-secondary">{{ lng('panel.cancel') }}</button>
<button type="submit" class="btn btn-success">{{ lng('panel.save') }}</button> <button type="submit" class="btn btn-primary">{{ lng('panel.save') }}</button>
</div>
</div> </div>
</div> </div>
</form> </form>

View File

@@ -1,9 +1,9 @@
{% macro fieldrow(id, field, norow = false, nohide = false, em = false) %} {% macro fieldrow(id, field, norow = false, nohide = false, em = false) %}
{% if field.visible is not defined or (field.visible is defined and field.visible) or nohide == true %} {% if field.visible is not defined or (field.visible is defined and field.visible) or nohide == true %}
{% if norow == false and field.type != 'hidden' %} {% if norow == false and field.type != 'hidden' %}
<div class="row mb-3 pb-3 border-bottom"> <div class="row g-0 formfield d-flex align-items-center">
{% if field.label is iterable %} {% if field.label is iterable %}
<label for="{{ id }}" class="col-sm-4 col-form-label"> <label for="{{ id }}" class="col-sm-4 col-form-label pe-3">
{% if em %} {% if em %}
<mark> <mark>
{% endif %} {% endif %}
@@ -15,7 +15,7 @@
{% endif %} {% endif %}
</label> </label>
{% else %} {% else %}
<label for="{{ id }}" class="col-sm-4 col-form-label"> <label for="{{ id }}" class="col-sm-4 col-form-label pe-3">
{% if em %} {% if em %}
<mark> <mark>
{% endif %} {% endif %}
@@ -27,7 +27,7 @@
{% endif %} {% endif %}
</label> </label>
{% endif %} {% endif %}
<div class="col-sm-8{% if field.type == 'infotext' %} d-flex align-items-center{% endif %}"> <div class="col-sm-8">
{% endif %} {% endif %}
{% if field.type == 'text' or field.type == 'password' or field.type == 'number' or field.type == 'file' or field.type == 'email' or field.type == 'url' or field.type == 'hidden' %} {% if field.type == 'text' or field.type == 'password' or field.type == 'number' or field.type == 'file' or field.type == 'email' or field.type == 'url' or field.type == 'hidden' %}
{{ _self.input(id, field) }} {{ _self.input(id, field) }}

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %} {% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %} {% block content %}
<div class="container max-w-lg flex align-content-center mt-5"> <div class="container max-w-lg flex align-content-center mt-5">
<img src="{{ basehref|default('') }}templates/Froxlor/assets/img/logo.png" class="filter-me" alt="Froxlor Server Management Panel"/> <img src="{{ basehref|default('') }}templates/Froxlor/assets/img/logo.png" class="filter-me" alt="Froxlor Server Management Panel"/>

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %} {% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block body %} {% block body %}
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %} {% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/userarea.html.twig" %} {% extends "Froxlor/userarea.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %} {% block content %}
{% include 'Froxlor/misc/alertbox.html.twig' %} {% include 'Froxlor/misc/alertbox.html.twig' %}
{% endblock %} {% endblock %}

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %} {% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %} {% block content %}
{% include 'Froxlor/misc/alertbox.html.twig' %} {% include 'Froxlor/misc/alertbox.html.twig' %}
{% endblock %} {% endblock %}

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %} {% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %} {% block content %}
<div class="container max-w-lg flex align-content-center mt-5"> <div class="container max-w-lg flex align-content-center mt-5">
<img src="templates/Sparkle/assets/img/logo.png" alt="Froxlor Server Management Panel" /> <img src="templates/Sparkle/assets/img/logo.png" alt="Froxlor Server Management Panel" />

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %} {% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %} {% block content %}
<div class="container my-auto"> <div class="container my-auto">
<div class="alert alert-warning fade show" role="alert"> <div class="alert alert-warning fade show" role="alert">

View File

@@ -1,8 +1,8 @@
<a class="btn {% if isnewerversion == 0 %}btn-light text-success{% else %}btn-warning{% endif %} btn-sm d-block me-2" {% if isnewerversion == 0 %} href="#" {% else %} href="admin_autoupdate.php?page=overview&s={{ s }}" {% endif %} title="{% if isnewerversion == 0 %}{{ additional_info }}{% else %}{{ message }}{% endif %}"> <a class="nav-link {% if isnewerversion == 0 %}text-success{% else %}text-warning{% endif %}" {% if isnewerversion == 0 %} href="#" {% else %} href="admin_autoupdate.php?page=overview&s={{ s }}" {% endif %} title="{% if isnewerversion == 0 %}{{ additional_info }}{% else %}{{ message }}{% endif %}">
{% if isnewerversion == 0 %} {% if isnewerversion == 0 %}
<i class="fa-solid fa-circle-check me-1"></i> <i class="fa-solid fa-circle-check me-1"></i>
{% else %} {% else %}
<i class="fa-solid fa-circle-exclamation me-1"></i> <i class="fa-solid fa-circle-exclamation me-1"></i>
{% endif %} {% endif %}
{{ version }} <span class="d-md-none d-xl-inline">{{ version }}</span>
</a> </a>

View File

@@ -1,52 +1,53 @@
{% extends "Froxlor/userarea.html.twig" %} {% extends "Froxlor/userarea.html.twig" %}
{% block heading %}
<h5>
<i class="fa-solid fa-gears"></i>
{{ lng('admin.serversettings') }}
{% if fields._group is defined %}&nbsp;&raquo;&nbsp;{{ fields._group.title }}
{% endif %}
</h5>
<span class="text-muted">Manage your Froxlor system</span>
{% endblock %}
{% block actions %}
<a class="btn btn-outline-primary" href="{{ linker({'section':'settings','page':'overview','part':'all'}) }}">
<i class="fa-solid fa-grip me-1"></i>
{{ lng('admin.configfiles.overview') }}
</a>
<a class="btn btn-outline-secondary" href="{{ linker({'section':'settings','page':'importexport'}) }}">
<i class="fa-solid fa-file-import me-1"></i>
{{ lng('admin.configfiles.importexport') }}
</a>
{% endblock %}
{% block content %} {% block content %}
<form action="{{ action|default(filename) }}" method="post" enctype="application/x-www-form-urlencoded" class="form">
<div class="row"> {% block settings %}
<div class="col-12 col-md-10 order-2 order-md-1"> <div class="row row-cols-2 row-cols-md-2 row-cols-xl-4 g-3">
{% for field in fields %}
<form action="{{ action|default(filename) }}" method="post" enctype="application/x-www-form-urlencoded" class="form"> <div class="col">
<h3 class="page-header"> <div class="card h-100 position-relative {% if not field.activated %}{% endif %}">
<i class="fa-solid fa-gears"></i> <div class="card-body d-flex overflow-hidden align-items-center">
{{ lng('admin.serversettings') }} <a href="{{ linker({'section':'settings','page':'overview','part':field.part}) }}" class="stretched-link">
{% if fields._group is defined %}&nbsp;&raquo;&nbsp;{{ fields._group.title }} <i class="{{ field.icon }} fa-2x me-4" style="width: 1em;"></i>
{% endif %} </a>
</h3> <div>
{{ field.title }}
{% block settings %} {% if field.info is defined and field.info is not empty %}
<div class="row row-cols-2 row-cols-md-4 row-cols-xl-6 g-3"> {{ field.info|raw }}
{% for field in fields %} {% endif %}
<div class="col">
<div class="card h-100 border {% if field.activated %}border-primary{% else %}border-secondary bg-light{% endif %}">
<div class="card-body text-center">
<a href="{{ linker({'section':'settings','page':'overview','part':field.part}) }}" class="btn btn-link stretched-link">
<i class="{{ field.icon }} fa-4x"></i>
</a>
<p class="card-text mt-2">{{ field.title }}
{% if field.info is defined and field.info is not empty %}<br><small>{{ field.info|raw }}</small>
{% endif %}
</p>
{% if field.activated == false %}
<small class="text-danger">{{ lng('panel.not_activated') }}</small>
{% endif %}
</div>
</div> </div>
</div> </div>
{% endfor %} {% if not field.activated %}
<div class="position-absolute top-0 end-0 p-1">
<span class="badge text-muted" style="background: #eee">{{ lng('panel.not_activated') }}</span>
</div>
{% endif %}
</div>
</div> </div>
{% endblock %} {% endfor %}
</div>
</form> {% endblock %}
</form>
</div>
<div class="col-12 col-md-2 order-1 order-md-2">
<a class="btn btn-primary d-block mb-2" href="{{ linker({'section':'settings','page':'overview','part':'all'}) }}">
<i class="fa-solid fa-grip me-1"></i>
{{ lng('admin.configfiles.overview') }}</a>
<a class="btn btn-secondary d-block mb-2" href="{{ linker({'section':'settings','page':'importexport'}) }}">
<i class="fa-solid fa-file-import me-1"></i>
{{ lng('admin.configfiles.importexport') }}</a>
</div>
</div>
{% endblock %} {% endblock %}

View File

@@ -31,20 +31,4 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
<div class="d-flex flex-shrink-0 p-3 user-info">
<div class="dropdown d-block flex-shrink-0">
<a href="#" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle" id="dropdownUser1" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fa-solid fa-user me-3"></i>
<strong>{{ userinfo.loginname }}</strong>
</a>
<ul class="dropdown-menu dropdown-menu-dark text-small shadow" aria-labelledby="dropdownUser1">
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ linker({'section': 'index', 'action': 'logout'}) }}">{{ lng('login.logout') }}</a></li>
</ul>
</div>
</div>
</nav> </nav>

View File

@@ -11,7 +11,8 @@ $(document).ready(function () {
}, },
error: function (request, status, error) { error: function (request, status, error) {
console.log(request, status, error) console.log(request, status, error)
$("#updatecheck").html('<div class="alert alert-warning" role="alert">Error checking version</div>'); let message = 'Can\'t check version';
$("#updatecheck").html('<a class="nav-link disabled text-warning" data-bs-toggle="tooltip" data-bs-placement="left" title="' + message + '"><i class="fa fa-exclamation-triangle"></i> <span class="d-md-none d-xl-inline">' + message + '</span></a>');
} }
}); });
} }

View File

@@ -1,63 +1,60 @@
@import "~@fortawesome/fontawesome-free/css/all"; @import "~@fortawesome/fontawesome-free/css/all";
.navbar { .form-control-plaintext {
background: darken($navbar-bg, 3); outline: none;
}
.navbar, .card {
@extend .shadow-sm;
} }
.page-header { .page-header {
margin-bottom: 2rem; margin-bottom: 2rem;
&:after { &:after {
margin-top: .5rem; margin-top: .5rem;
display: block; display: block;
height: 3px; height: 3px;
width: 100px; width: 100px;
background: $froxlor-blue-dark; background: $froxlor-blue-dark;
border-radius: 3px; border-radius: 3px;
content: ' '; content: ' ';
} }
}
.progress-thin {
height: 3px;
} }
.alert-icon { .alert-icon {
padding: .5rem; padding: .5rem;
background: rgba(0, 0, 0, .15); background: rgba(0, 0, 0, .15);
text-align: center; text-align: center;
border-radius: $border-radius; border-radius: $border-radius;
margin-right: .75rem; margin-right: .75rem;
} }
.max-w-420 { .max-w-420 {
max-width: 420px; max-width: 420px;
} }
.max-w-xs { .max-w-xs {
max-width: 575.98px; max-width: 575.98px;
} }
.max-w-lg { .max-w-lg {
max-width: 991.98px; max-width: 991.98px;
}
.max-h-before-header {
max-height: calc(100vh - ($spacer * 3.5));
} }
.rounded-tl-bl { .rounded-tl-bl {
border-radius: $border-radius 0 $border-radius 0; border-radius: $border-radius 0 $border-radius 0;
} }
footer { .progress-thin {
@extend .text-muted; height: .5rem;
} }
.logcontent { .logcontent {
width: 100%; width: 100%;
} }
.formfield {
padding: 1rem $spacer;
border-bottom: $border-color solid 1px;
&:last-child {
border-bottom: none;
}
}

View File

@@ -1,13 +1,24 @@
.card { .card {
margin-bottom: $spacer * 1.5; @extend .shadow-sm;
margin-bottom: $spacer * 1.5;
.card-header { .card-header {
border-bottom: #e5e5e5 solid 1px; border-bottom: #e5e5e5 solid 1px;
font-weight: bold; font-weight: bold;
} }
.card-body {
p { .card-body {
@extend .card-text; p {
} @extend .card-text;
} }
}
&.deactivated {
@extend .text-muted;
background: lighten($light-bg, 3%);
i {
@extend .text-muted;
}
}
} }

View File

@@ -0,0 +1,12 @@
.dropdown {
.dropdown-menu {
.dropdown-item {
i {
width: 1rem;
margin-right: 1rem;
text-align: center;
color: $text-muted;
}
}
}
}

View File

@@ -0,0 +1,8 @@
footer {
@extend .small;
a {
@extend .text-muted;
@extend .text-decoration-none;
}
}

View File

@@ -1,22 +1,48 @@
.navbar { .navbar {
background: darken($navbar-bg, 3); background: darken($navbar-bg, 3);
}
.navbar-brand {
padding: 1rem;
} }
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
.navbar { .navbar {
.navbar-brand { background: $white;
background: $dark;
width: $sidebar-width; .navbar-brand {
} background: $dark;
} width: $sidebar-width;
margin-right: 0;
flex-shrink: 0;
}
}
} }
@include media-breakpoint-down(md) { @include media-breakpoint-down(md) {
.navbar { .form-control-plaintext {
background: $dark; color: $white;
} }
.navbar {
background: $dark;
.navbar-light .navbar-toggler-icon { .navbar-nav {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); .nav-link {
} color: $white;
&:hover {
color: rgba(255,255,255,.45);
}
}
}
}
.navbar-light {
.navbar-toggler {
border-color: transparent;
}
.navbar-toggler-icon {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
}
} }

View File

@@ -1,38 +1,49 @@
.sidebar { .sidebar, .sub-sidebar {
width: $sidebar-width; width: $sidebar-width;
@extend .shadow; }
&.collapsing { .sidebar {
transition: none; @extend .shadow;
} width: $sidebar-width;
.user-info { &.collapsing {
background: darken($dark, 2); transition: none;
} }
>.nav { .user-info {
>.nav-item { background: darken($dark, 2);
>.nav-link { }
i {
margin-right: 1rem; > .nav {
width: 1rem; > .nav-item {
text-align: center; > .nav-link {
opacity: .5; i {
} margin-right: 1rem;
&:not(.collapsed) { width: 1rem;
background: darken($dark, 4); text-align: center;
border-left: $primary solid 3px; opacity: .5;
padding-left: calc(1rem - 3px); }
}
} &:not(.collapsed) {
>.collapse, >.collapsing { background: darken($dark, 4);
background: darken($dark, 2); border-left: $primary solid 3px;
padding-left: calc(1rem - 3px);
a { }
opacity: .78; }
margin-left: 1.25rem;
} > .collapse, > .collapsing {
} background: darken($dark, 2);
}
} a {
opacity: .78;
margin-left: 1rem;
}
}
}
}
}
.sub-sidebar {
@extend .shadow-sm;
background: $white;
} }

View File

@@ -6,7 +6,9 @@
// Theme // Theme
@import "global"; @import "global";
@import "components/card";
@import "components/dropdown";
@import "components/footer";
@import "components/form";
@import "components/navbar"; @import "components/navbar";
@import "components/sidebar"; @import "components/sidebar";
@import "components/card";
@import "components/form";

View File

@@ -9,7 +9,6 @@ $froxlor-blue-light: #62c8f4;
$froxlor-blue-dark: #1871a2; $froxlor-blue-dark: #1871a2;
$primary: $froxlor-blue-dark; $primary: $froxlor-blue-dark;
$secondary: $dark-bg;
$info: $froxlor-blue-light; $info: $froxlor-blue-light;
$warning: #FBBF24; $warning: #FBBF24;
$danger: #E11D48; $danger: #E11D48;
@@ -21,6 +20,10 @@ $alert-border-width: 0;
$list-group-item-color-scale: 0; $list-group-item-color-scale: 0;
$list-group-item-bg-scale: 0; $list-group-item-bg-scale: 0;
$input-bg: lighten($light-bg, 5%);
$font-size-root: 16px;
// Space // Space
$spacer: 1.25rem; $spacer: 1.25rem;
@@ -29,7 +32,7 @@ $body-bg: $light-bg;
$body-color: $light-font-color; $body-color: $light-font-color;
// Borders // Borders
$border-radius: 0.5rem; // $border-radius: 0.5rem;
// Links // Links
$links: $froxlor-blue-dark; $links: $froxlor-blue-dark;
@@ -38,7 +41,7 @@ $links: $froxlor-blue-dark;
$navbar-bg: #ffffff; $navbar-bg: #ffffff;
// Sidebar // Sidebar
$sidebar-width: 280px; $sidebar-width: 256px;
// Card // Card
$card-cap-bg: none; $card-cap-bg: none;

View File

@@ -2,7 +2,7 @@
<div class="progress progress-thin"> <div class="progress progress-thin">
<div class="progress-bar {{ data.style }}" style="width: {{ data.percent }}%;"></div> <div class="progress-bar {{ data.style }}" style="width: {{ data.percent }}%;"></div>
</div> </div>
<div class="text-end"> <div class="text-end small">
{% if data.infotext is not empty %} {% if data.infotext is not empty %}
<i class="fa-solid fa-circle-info" data-toggle="tooltip" data-placement="right" title="{{ data.infotext|raw }}"></i> <i class="fa-solid fa-circle-info" data-toggle="tooltip" data-placement="right" title="{{ data.infotext|raw }}"></i>
{% endif %} {% endif %}
@@ -31,14 +31,27 @@
{% macro link(data) %} {% macro link(data) %}
{% apply spaceless %} {% apply spaceless %}
<a href="{{ data.href }}" {% if data.class is defined %} class="{{ data.class }}" {% endif %} {% if data.target is defined %} target="{{ data.target }}" {% endif %}{% if data.title is defined %} title="{{ data.title }}" {% endif %}> <a href="{{ data.href }}" {% if data.class is defined %} class="{{ data.class }}" {% endif %} {% if data.target is defined %} target="{{ data.target }}" {% endif %}{% if data.title is defined %} title="{{ data.title }}" {% endif %}>
{% if data.icon is defined %} {% if data.icon is defined %}
<i class="{{ data.icon }}"></i> <i class="{{ data.icon }}"></i>
{% endif %} {% endif %}
{% if data.text is defined %} {% if data.text is defined %}
{{ data.text }} {{ data.text }}
{% endif %} {% endif %}
</a> </a>
{% endapply %}
{% endmacro %}
{% macro button(data) %}
{% apply spaceless %}
<a class="{% if data.class is defined %}btn btn-sm {{ data.class }}{% else %}btn btn-sm btn-outline-secondary{% endif %}" href="{{ data.href }}" {% if data.target is defined %} target="{{ data.target }}" {% endif %}{% if data.title is defined %} title="{{ data.title }}" {% endif %}>
{% if data.icon is defined %}
<i class="{{ data.icon }}"></i>
{% endif %}
{% if data.text is defined %}
{{ data.text }}
{% endif %}
</a>
{% endapply %} {% endapply %}
{% endmacro %} {% endmacro %}
@@ -55,7 +68,7 @@
{% macro actions(data) %} {% macro actions(data) %}
{% for action in data %} {% for action in data %}
{% if action.visible is not defined or action.visible is defined and action.visible %} {% if action.visible is not defined or action.visible is defined and action.visible %}
{{ _self.link(action) }} {{ _self.button(action) }}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endmacro %} {% endmacro %}

View File

@@ -1,52 +1,51 @@
{% macro paging(pagination) %} {% macro paging(pagination) %}
{% if pagination.last_page > 1 %} {% if pagination.last_page > 1 %}
<div class="card-footer border-top"> <div class="card-footer border-top">
<nav aria-label="Pagination"> <nav aria-label="Pagination">
<ul class="pagination justify-content-center"> <ul class="pagination justify-content-center mb-0">
{% if pagination.current_page == 1 %} {% if pagination.current_page == 1 %}
<li class="page-item disabled"> <li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true"> <a class="page-link" href="#" tabindex="-1" aria-disabled="true">
<i class="fa-solid fa-backward-fast"></i> <i class="fa-solid fa-angles-left"></i>
</a> </a>
</li> </li>
<li class="page-item disabled"> <li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true"> <a class="page-link" href="#" tabindex="-1" aria-disabled="true">
<i class="fa-solid fa-backward"></i> <i class="fa-solid fa-chevron-left"></i>
</a> </a>
</li> </li>
{% elseif pagination.current_page > 1 %} {% elseif pagination.current_page > 1 %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno=1" tabindex="-1"> <a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno=1" tabindex="-1">
<i class="fa-solid fa-backward-fast"></i> <i class="fa-solid fa-angles-left"></i>
</a> </a>
</li> </li>
<li class="page-item"> <li class="page-item">
<a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno={{ pagination.current_page - 1 }}" tabindex="-1"> <a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno={{ pagination.current_page - 1 }}" tabindex="-1">
<i class="fa-solid fa-backward"></i> <i class="fa-solid fa-chevron-left"></i>
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% if pagination.current_page < pagination.last_page %} {% if pagination.current_page < pagination.last_page %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno={{ pagination.current_page + 1 }}" tabindex="-1"> <a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno={{ pagination.current_page + 1 }}" tabindex="-1">
<i class="fa-solid fa-forward"></i> <i class="fa-solid fa-chevron-right"></i>
</a> </a>
</li> </li>
<li class="page-item"> <li class="page-item">
<a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno={{ pagination.last_page }}" tabindex="-1"> <a class="page-link" href="?s={{ s }}&page={{ page }}&action={{ action }}&pageno={{ pagination.last_page }}" tabindex="-1">
<i class="fa-solid fa-forward-fast"></i> <i class="fa-solid fa-angles-right"></i>
</a> </a>
</li> </li>
{% else %} {% else %}
<li class="page-item disabled"> <li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true"> <a class="page-link" href="#" tabindex="-1" aria-disabled="true">
<i class="fa-solid fa-forward"></i> <i class="fa-solid fa-chevron-right"></i>
</a> </a>
</li> </li>
<li class="page-item disabled"> <li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true"> <a class="page-link" href="#" tabindex="-1" aria-disabled="true">
<i class="fa-solid fa-forward-fast"></i> <i class="fa-solid fa-angles-right"></i>
</a> </a>
</li> </li>
{% endif %} {% endif %}

View File

@@ -4,15 +4,6 @@
{% import "Froxlor/table/pagination.html.twig" as pagination %} {% import "Froxlor/table/pagination.html.twig" as pagination %}
<form action="{{ action|default("") }}" method="post" enctype="application/x-www-form-urlencoded" class="form"> <form action="{{ action|default("") }}" method="post" enctype="application/x-www-form-urlencoded" class="form">
{% if listing.title is not empty %}
<h3 class="page-header">
{% if listing.icon is not empty %}
<i class="{{ listing.icon }} me-1"></i>
{% endif %}
{{ listing.title }}
</h3>
{% endif %}
{% if listing.table.tr|length == 0 %} {% if listing.table.tr|length == 0 %}
<div class="alert alert-info" role="alert"> <div class="alert alert-info" role="alert">
<h4 class="alert-heading">{{ lng('admin.note') }}</h4> <h4 class="alert-heading">{{ lng('admin.note') }}</h4>
@@ -20,7 +11,7 @@
</div> </div>
{% else %} {% else %}
<div class="card table-responsive"> <div class="card table-responsive">
<table class="table table-borderless table-striped table-sm mb-0 px-3"> <table class="table table-borderless table-striped align-middle mb-0 px-3">
<thead> <thead>
<tr> <tr>
{% for key,th in listing.table.th %} {% for key,th in listing.table.th %}

View File

@@ -20,8 +20,8 @@
aria-valuemax="{% if available < 0 %}100{% else %}{{ available }}{% endif %}"></div> aria-valuemax="{% if available < 0 %}100{% else %}{{ available }}{% endif %}"></div>
</div> </div>
{% if assigned is not empty %} {% if assigned is not empty %}
<div class="progress progress-thin my-auto"> <div class="progress progress-thin mt-2 my-auto">
<div class="progress-bar bg-info" role="progressbar" <div class="progress-bar bg-primary" role="progressbar"
style="width:{% if available > 0 %}{{ (assigned / available) * 100|round }}{% else %}1{% endif %}%;" style="width:{% if available > 0 %}{{ (assigned / available) * 100|round }}{% else %}1{% endif %}%;"
aria-valuenow="{{ assigned }}" aria-valuemin="0" aria-valuenow="{{ assigned }}" aria-valuemin="0"
aria-valuemax="{{ available }}"></div> aria-valuemax="{{ available }}"></div>

View File

@@ -1,5 +1,23 @@
{% extends "Froxlor/userarea.html.twig" %} {% extends "Froxlor/userarea.html.twig" %}
{% block heading %}
{% if formdata.title is not empty %}
<div>
<h5 class="mb-1">
{% if form_data.image is not empty %}
<i class="{{ form_data.image }} me-1"></i>
{% endif %}
{{ formdata.title }}
</h5>
{% if formdata.description is not empty %}
<span class="text-muted">{{ formdata.description }}</span>
{% endif %}
</div>
{% endif %}
{% endblock %}
{% block content %} {% block content %}
{% import "Froxlor/form/form.html.twig" as form %} {% import "Froxlor/form/form.html.twig" as form %}

View File

@@ -1,26 +1,48 @@
{% extends "Froxlor/userarea.html.twig" %} {% extends "Froxlor/userarea.html.twig" %}
{% block content %} {% block heading %}
<div class="row">
<div class="col-12 {% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %}col-md-10 order-2 order-md-1{% endif %}"> {% if listing.title is not empty %}
{% import "Froxlor/table/table.html.twig" as table %} <h5 class="mb-1">
{{ table.table(listing) }} {% if listing.icon is not empty %}
</div> <i class="{{ listing.icon }} me-1"></i>
{% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %} {% endif %}
<div class="col-12 col-md-2 order-1 order-md-2"> {{ listing.title }}
{% if actions_links is iterable %} </h5>
{% for link in actions_links %} {% if listing.description is not empty %}
<a class="btn {{ link.class|default('btn-success') }} d-block mb-2" href="{{ link.href|raw }}"> <span class="text-muted mt-2">{{ listing.description }}</span>
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }} me-1"></i>
{{ link.label }}</a>
{% endfor %}
{% endif %}
{% if entity_info is defined and entity_info is not empty %}
<div class="alert alert-info" role="alert">
{{ entity_info|raw }}
</div>
{% endif %}
</div>
{% endif %} {% endif %}
</div> {% endif %}
{% endblock %}
{% block actions %}
{% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %}
<div>
{% if actions_links is iterable %}
{% for link in actions_links %}
<a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}">
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i><span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>
</a>
{% endfor %}
{% endif %}
{# TODO: eventually not used anymore because of using a documentation link
{% if entity_info is defined and entity_info is not empty %}
<div class="alert alert-info" role="alert">
{{ entity_info|raw }}
</div>
{% endif %}
#}
</div>
{% endif %}
{% endblock %}
{% block content %}
{% import "Froxlor/table/table.html.twig" as table %}
{{ table.table(listing) }}
{% endblock %} {% endblock %}

View File

@@ -17,9 +17,9 @@
</div> </div>
{% endif %} {% endif %}
<nav class="navbar navbar-expand-md navbar-light py-0"> <nav class="navbar navbar-expand-md navbar-light p-0 {% if not block('heading') %}shadow-sm{% endif %}">
<div class="container-fluid gx-0"> <div class="container-fluid gx-0">
<a class="navbar-brand p-3" href="{{ linker({'section': 'index'}) }}"> <a class="navbar-brand" href="{{ linker({'section': 'index'}) }}">
<img src="{{ header_logo }}" alt="" width="auto" height="24" class="d-inline-block align-text-top"> <img src="{{ header_logo }}" alt="" width="auto" height="24" class="d-inline-block align-text-top">
</a> </a>
<div class="me-3 me-sm-0"> <div class="me-3 me-sm-0">
@@ -30,28 +30,27 @@
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
</div> </div>
<form id="search" class="position-relative" method="post"> <div class="collapse navbar-collapse px-3 px-lg-5" id="navbar">
<div class="input-group"> <form id="search" class="d-flex position-relative" method="post">
<input title="search" type="search" class="form-control-plaintext" placeholder="Search for ..." style="outline: none"> <div class="input-group">
</div> <input title="search" type="search" class="form-control-plaintext" placeholder="Search for ..." style="outline: none">
<ul id="search-dropdown" class="bg-white border list-group list-group-flush position-absolute" style="display:none; z-index: 50; max-height: 300px; overflow-y: scroll"></ul> </div>
</form> <ul id="search-dropdown" class="bg-white border list-group list-group-flush position-absolute" style="top: 2.5rem; display:none; z-index: 50; max-height: 300px; overflow-y: scroll"></ul>
<div class="collapse navbar-collapse justify-content-end px-3" id="navbar"> </form>
<ul class="navbar-nav align-items-center"> <ul class="navbar-nav ms-auto">
{% if userinfo.adminsession == 1 %} {% if userinfo.adminsession == 1 %}
<li class="nav-item text-nowrap d-block" id="updatecheck"> <li class="nav-item" id="updatecheck"></li>
</li>
{% endif %} {% endif %}
<li class="nav-item text-nowrap d-block me-2"> <li class="nav-item">
<a class="btn btn-primary btn-sm d-block" href="{{ linker({'section': 'index'}) }}"> <a class="nav-link" href="{{ linker({'section': 'index'}) }}">
<i class="fa fa-dashboard"></i> {{ lng('panel.dashboard') }} {{ lng('panel.dashboard') }}
</a> </a>
</li> </li>
<li class="nav-item dropdown me-2"> <li class="nav-item dropdown">
<a class="btn btn-secondary btn-sm d-block dropdown-toggle" href="#" id="navbarOpts" role="button" data-bs-toggle="dropdown" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarOpts" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fa fa-gears"></i> {{ lng('panel.options') }} {{ userinfo.loginname }}
</a> </a>
<ul class="dropdown-menu" aria-labelledby="navbarOpts"> <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarOpts">
<li> <li>
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'change_password'}) }}"><i class="fa-solid fa-lock"></i> {{ lng('login.password') }}</a> <a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'change_password'}) }}"><i class="fa-solid fa-lock"></i> {{ lng('login.password') }}</a>
</li> </li>
@@ -90,8 +89,8 @@
Switch back</a> Switch back</a>
</li> </li>
endif --> endif -->
<li class="nav-item text-nowrap d-block"> <li class="nav-item">
<a class="btn btn-link" title="{{ lng('login.logout') }}" href="{{ linker({'section': 'index', 'action': 'logout'}) }}"> <a class="btn btn-link pe-0" title="{{ lng('login.logout') }}" href="{{ linker({'section': 'index', 'action': 'logout'}) }}">
<i class="fas fa-power-off"></i> <i class="fas fa-power-off"></i>
</a> </a>
</li> </li>
@@ -102,15 +101,38 @@
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<div class="d-flex flex-grow-1 overflow-hidden"> <div class="d-flex flex-grow-1">
{{ include('Froxlor/sidebarmenu.html.twig') }} {{ include('Froxlor/sidebar.html.twig') }}
<main role="main" class="d-flex flex-column flex-grow-1 px-5 pt-4 pb-0 overflow-auto max-h-before-header"> <div class="d-flex flex-grow-1 overflow-hidden">
<section class="flex-grow-1"> {# TODO: eventually planned for settings page ...
{% block content %}{% endblock %} <div class="sub-sidebar border-end border-top d-none d-sm-block flex-shrink-0 py-3">
</section> <span class="px-3 text-muted">Settings</span>
<nav class="nav flex-column">
<a class="nav-link active" aria-current="page" href="#">Active</a>
<a class="nav-link" href="#">Link</a>
<a class="nav-link" href="#">Link</a>
<a class="nav-link disabled">Disabled</a>
</nav>
</div>
#}
{{ include('Froxlor/footer.html.twig') }} <main class="d-flex flex-column flex-grow-1 overflow-auto">
</main> {% if block('heading') %}
<section class="py-3 px-3 px-lg-5 bg-white shadow-sm border-top d-flex justify-content-between align-items-center">
<div>{% block heading %}{% endblock %}</div>
<div>{% block actions %}{% endblock %}</div>
</section>
{% endif %}
<section class="flex-grow-1 p-3 p-lg-5">
{% block content %}{% endblock %}
</section>
{{ include('Froxlor/footer.html.twig') }}
</main>
{% block subsidebar %}{% endblock %}
</div>
</div> </div>
{% endblock %} {% endblock %}