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
{
$percent = 0;
$style = 'bg-info';
$style = 'bg-primary';
$text = PhpHelper::sizeReadable($attributes[$field . '_used'] * $size_factor, null, 'bi') . ' / ' . UI::getLng('panel.unlimited');
if ((int)$attributes[$field] >= 0) {
if (($attributes[$field] / 100) * $report_max < $attributes[$field . '_used']) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -71,7 +71,7 @@ return [
'delete' => [
'icon' => 'fa fa-trash',
'title' => $lng['panel']['delete'],
'class' => 'text-danger',
'class' => 'btn-danger',
'href' => [
'section' => 'index',
'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 }}
{% endif %}
{% block custom_js %}{% endblock %}
<title>Froxlor
{% if page_title %}
|
{{ page_title }}
{% endif %}
</title>
<title>Froxlor{% if page_title %} | {{ page_title }}{% endif %}</title>
</head>
<body {% if body_class is defined %}class="{{ body_class }}"{% endif %}>
{{ global_errors|raw }}
<body class="min-vh-100 d-flex flex-column">
{% block navigation %}{% endblock %}
{% block body %}

View File

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

View File

@@ -3,15 +3,6 @@
{% import "Froxlor/form/formfields.html.twig" as formfields %}
<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 %}
<div class="card mb-3">
{% if section.title is not empty %}
@@ -22,7 +13,7 @@
{{ section.title }}
</div>
{% endif %}
<div class="card-body">
<div class="formfields">
{% for id,field in section.fields %}
{{ formfields.fieldrow(id, field) }}
{% endfor %}
@@ -31,8 +22,7 @@
{% endfor %}
<!-- submit buttons -->
<div class="card mb-3">
<div class="card-body">
<div>
{% if hiddenid is not empty %}
<input type="hidden" name="id" value="{{ hiddenid }}"/>
{% endif %}
@@ -41,10 +31,9 @@
<input type="hidden" name="action" value="{{ action }}"/>
<input type="hidden" name="send" value="send"/>
<div class="col-12 text-center">
<button type="reset" class="btn btn-warning">{{ lng('panel.cancel') }}</button>
<button type="submit" class="btn btn-success">{{ lng('panel.save') }}</button>
</div>
<div class="col-12 text-end">
<button type="reset" class="btn btn-outline-secondary">{{ lng('panel.cancel') }}</button>
<button type="submit" class="btn btn-primary">{{ lng('panel.save') }}</button>
</div>
</div>
</form>

View File

@@ -1,9 +1,9 @@
{% 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 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 %}
<label for="{{ id }}" class="col-sm-4 col-form-label">
<label for="{{ id }}" class="col-sm-4 col-form-label pe-3">
{% if em %}
<mark>
{% endif %}
@@ -15,7 +15,7 @@
{% endif %}
</label>
{% 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 %}
<mark>
{% endif %}
@@ -27,7 +27,7 @@
{% endif %}
</label>
{% endif %}
<div class="col-sm-8{% if field.type == 'infotext' %} d-flex align-items-center{% endif %}">
<div class="col-sm-8">
{% 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' %}
{{ _self.input(id, field) }}

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %}
<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"/>

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %}
<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" />

View File

@@ -1,7 +1,5 @@
{% extends "Froxlor/base.html.twig" %}
{% set body_class = "min-vh-100 d-flex align-items-center" %}
{% block content %}
<div class="container my-auto">
<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 %}
<i class="fa-solid fa-circle-check me-1"></i>
{% else %}
<i class="fa-solid fa-circle-exclamation me-1"></i>
{% endif %}
{{ version }}
<span class="d-md-none d-xl-inline">{{ version }}</span>
</a>

View File

@@ -1,52 +1,53 @@
{% extends "Froxlor/userarea.html.twig" %}
{% block content %}
<div class="row">
<div class="col-12 col-md-10 order-2 order-md-1">
<form action="{{ action|default(filename) }}" method="post" enctype="application/x-www-form-urlencoded" class="form">
<h3 class="page-header">
{% 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 %}
</h3>
</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 %}
<form action="{{ action|default(filename) }}" method="post" enctype="application/x-www-form-urlencoded" class="form">
{% block settings %}
<div class="row row-cols-2 row-cols-md-4 row-cols-xl-6 g-3">
<div class="row row-cols-2 row-cols-md-2 row-cols-xl-4 g-3">
{% for field in fields %}
<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>
<div class="card h-100 position-relative {% if not field.activated %}{% endif %}">
<div class="card-body d-flex overflow-hidden align-items-center">
<a href="{{ linker({'section':'settings','page':'overview','part':field.part}) }}" class="stretched-link">
<i class="{{ field.icon }} fa-2x me-4" style="width: 1em;"></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>
<div>
{{ field.title }}
{% if field.info is defined and field.info is not empty %}
{{ field.info|raw }}
{% endif %}
</div>
</div>
{% 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>
{% endfor %}
</div>
{% 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 %}

View File

@@ -31,20 +31,4 @@
{% endif %}
{% endfor %}
</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>

View File

@@ -11,7 +11,8 @@ $(document).ready(function () {
},
error: function (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,11 +1,7 @@
@import "~@fortawesome/fontawesome-free/css/all";
.navbar {
background: darken($navbar-bg, 3);
}
.navbar, .card {
@extend .shadow-sm;
.form-control-plaintext {
outline: none;
}
.page-header {
@@ -22,10 +18,6 @@
}
}
.progress-thin {
height: 3px;
}
.alert-icon {
padding: .5rem;
background: rgba(0, 0, 0, .15);
@@ -46,18 +38,23 @@
max-width: 991.98px;
}
.max-h-before-header {
max-height: calc(100vh - ($spacer * 3.5));
}
.rounded-tl-bl {
border-radius: $border-radius 0 $border-radius 0;
}
footer {
@extend .text-muted;
.progress-thin {
height: .5rem;
}
.logcontent {
width: 100%;
}
.formfield {
padding: 1rem $spacer;
border-bottom: $border-color solid 1px;
&:last-child {
border-bottom: none;
}
}

View File

@@ -1,13 +1,24 @@
.card {
@extend .shadow-sm;
margin-bottom: $spacer * 1.5;
.card-header {
border-bottom: #e5e5e5 solid 1px;
font-weight: bold;
}
.card-body {
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

@@ -2,21 +2,47 @@
background: darken($navbar-bg, 3);
}
.navbar-brand {
padding: 1rem;
}
@include media-breakpoint-up(md) {
.navbar {
background: $white;
.navbar-brand {
background: $dark;
width: $sidebar-width;
margin-right: 0;
flex-shrink: 0;
}
}
}
@include media-breakpoint-down(md) {
.form-control-plaintext {
color: $white;
}
.navbar {
background: $dark;
.navbar-nav {
.nav-link {
color: $white;
&:hover {
color: rgba(255,255,255,.45);
}
}
}
}
.navbar-light .navbar-toggler-icon {
.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,6 +1,10 @@
.sidebar {
.sidebar, .sub-sidebar {
width: $sidebar-width;
}
.sidebar {
@extend .shadow;
width: $sidebar-width;
&.collapsing {
transition: none;
@@ -10,29 +14,36 @@
background: darken($dark, 2);
}
>.nav {
>.nav-item {
>.nav-link {
> .nav {
> .nav-item {
> .nav-link {
i {
margin-right: 1rem;
width: 1rem;
text-align: center;
opacity: .5;
}
&:not(.collapsed) {
background: darken($dark, 4);
border-left: $primary solid 3px;
padding-left: calc(1rem - 3px);
}
}
>.collapse, >.collapsing {
> .collapse, > .collapsing {
background: darken($dark, 2);
a {
opacity: .78;
margin-left: 1.25rem;
margin-left: 1rem;
}
}
}
}
}
.sub-sidebar {
@extend .shadow-sm;
background: $white;
}

View File

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

View File

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

View File

@@ -2,7 +2,7 @@
<div class="progress progress-thin">
<div class="progress-bar {{ data.style }}" style="width: {{ data.percent }}%;"></div>
</div>
<div class="text-end">
<div class="text-end small">
{% if data.infotext is not empty %}
<i class="fa-solid fa-circle-info" data-toggle="tooltip" data-placement="right" title="{{ data.infotext|raw }}"></i>
{% endif %}
@@ -42,6 +42,19 @@
{% 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 %}
{% endmacro %}
{% macro domainWithSan(data) %}
{{ data.domain }}
{% if data.san is not empty %}
@@ -55,7 +68,7 @@
{% macro actions(data) %}
{% for action in data %}
{% if action.visible is not defined or action.visible is defined and action.visible %}
{{ _self.link(action) }}
{{ _self.button(action) }}
{% endif %}
{% endfor %}
{% endmacro %}

View File

@@ -1,52 +1,51 @@
{% macro paging(pagination) %}
{% if pagination.last_page > 1 %}
<div class="card-footer border-top">
<nav aria-label="Pagination">
<ul class="pagination justify-content-center">
<ul class="pagination justify-content-center mb-0">
{% if pagination.current_page == 1 %}
<li class="page-item disabled">
<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>
</li>
<li class="page-item disabled">
<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>
</li>
{% elseif pagination.current_page > 1 %}
<li class="page-item">
<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>
</li>
<li class="page-item">
<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>
</li>
{% endif %}
{% if pagination.current_page < pagination.last_page %}
<li class="page-item">
<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>
</li>
<li class="page-item">
<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>
</li>
{% else %}
<li class="page-item disabled">
<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>
</li>
<li class="page-item disabled">
<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>
</li>
{% endif %}

View File

@@ -4,15 +4,6 @@
{% import "Froxlor/table/pagination.html.twig" as pagination %}
<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 %}
<div class="alert alert-info" role="alert">
<h4 class="alert-heading">{{ lng('admin.note') }}</h4>
@@ -20,7 +11,7 @@
</div>
{% else %}
<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>
<tr>
{% for key,th in listing.table.th %}

View File

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

View File

@@ -1,5 +1,23 @@
{% 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 %}
{% import "Froxlor/form/form.html.twig" as form %}

View File

@@ -1,26 +1,48 @@
{% extends "Froxlor/userarea.html.twig" %}
{% block content %}
<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 %}">
{% import "Froxlor/table/table.html.twig" as table %}
{{ table.table(listing) }}
</div>
{% block heading %}
{% if listing.title is not empty %}
<h5 class="mb-1">
{% if listing.icon is not empty %}
<i class="{{ listing.icon }} me-1"></i>
{% endif %}
{{ listing.title }}
</h5>
{% if listing.description is not empty %}
<span class="text-muted mt-2">{{ listing.description }}</span>
{% endif %}
{% endif %}
{% endblock %}
{% block actions %}
{% if actions_links is iterable or (entity_info is defined and entity_info is not empty) %}
<div class="col-12 col-md-2 order-1 order-md-2">
<div>
{% if actions_links is iterable %}
{% for link in actions_links %}
<a class="btn {{ link.class|default('btn-success') }} d-block mb-2" href="{{ link.href|raw }}">
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }} me-1"></i>
{{ link.label }}</a>
<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 %}
</div>
{% endblock %}
{% block content %}
{% import "Froxlor/table/table.html.twig" as table %}
{{ table.table(listing) }}
{% endblock %}

View File

@@ -17,9 +17,9 @@
</div>
{% 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">
<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">
</a>
<div class="me-3 me-sm-0">
@@ -30,28 +30,27 @@
<span class="navbar-toggler-icon"></span>
</button>
</div>
<form id="search" class="position-relative" method="post">
<div class="collapse navbar-collapse px-3 px-lg-5" id="navbar">
<form id="search" class="d-flex position-relative" method="post">
<div class="input-group">
<input title="search" type="search" class="form-control-plaintext" placeholder="Search for ..." style="outline: none">
</div>
<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>
<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>
</form>
<div class="collapse navbar-collapse justify-content-end px-3" id="navbar">
<ul class="navbar-nav align-items-center">
<ul class="navbar-nav ms-auto">
{% if userinfo.adminsession == 1 %}
<li class="nav-item text-nowrap d-block" id="updatecheck">
</li>
<li class="nav-item" id="updatecheck"></li>
{% endif %}
<li class="nav-item text-nowrap d-block me-2">
<a class="btn btn-primary btn-sm d-block" href="{{ linker({'section': 'index'}) }}">
<i class="fa fa-dashboard"></i> {{ lng('panel.dashboard') }}
<li class="nav-item">
<a class="nav-link" href="{{ linker({'section': 'index'}) }}">
{{ lng('panel.dashboard') }}
</a>
</li>
<li class="nav-item dropdown me-2">
<a class="btn btn-secondary btn-sm d-block dropdown-toggle" href="#" id="navbarOpts" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fa fa-gears"></i> {{ lng('panel.options') }}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarOpts" role="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ userinfo.loginname }}
</a>
<ul class="dropdown-menu" aria-labelledby="navbarOpts">
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarOpts">
<li>
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'change_password'}) }}"><i class="fa-solid fa-lock"></i> {{ lng('login.password') }}</a>
</li>
@@ -90,8 +89,8 @@
Switch back</a>
</li>
endif -->
<li class="nav-item text-nowrap d-block">
<a class="btn btn-link" title="{{ lng('login.logout') }}" href="{{ linker({'section': 'index', 'action': 'logout'}) }}">
<li class="nav-item">
<a class="btn btn-link pe-0" title="{{ lng('login.logout') }}" href="{{ linker({'section': 'index', 'action': 'logout'}) }}">
<i class="fas fa-power-off"></i>
</a>
</li>
@@ -102,15 +101,38 @@
{% endblock %}
{% block body %}
<div class="d-flex flex-grow-1 overflow-hidden">
{{ include('Froxlor/sidebarmenu.html.twig') }}
<div class="d-flex flex-grow-1">
{{ 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">
<section class="flex-grow-1">
<div class="d-flex flex-grow-1 overflow-hidden">
{# TODO: eventually planned for settings page ...
<div class="sub-sidebar border-end border-top d-none d-sm-block flex-shrink-0 py-3">
<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>
#}
<main class="d-flex flex-column flex-grow-1 overflow-auto">
{% 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>
{% endblock %}