feat(frontend): style and theme overhaul

This commit is contained in:
Julian Lobbes 2022-12-03 01:27:24 +01:00
parent ed4919ef8c
commit 0f2e78c2ac
49 changed files with 745 additions and 553 deletions

View File

@ -16,6 +16,7 @@ services:
- ./lumi2/ldap.py:/app/lumi2/ldap.py:ro
- ./lumi2/logging.py:/app/lumi2/logging.py:ro
- ./lumi2/static/css:/app/lumi2/static/css:ro
- ./lumi2/static/fonts:/app/lumi2/static/fonts:ro
- ./lumi2/static/images/base:/app/lumi2/static/images/base:ro
- ./lumi2/static/images/default:/app/lumi2/static/images/default:ro
- ./lumi2/static/js:/app/lumi2/static/js:ro

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

145
lumi2/static/css/fonts.css Normal file
View File

@ -0,0 +1,145 @@
/* Montserrat */
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-thin-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-thin-webfont.woff') format('woff');
font-weight: 100;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-thinitalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-thinitalic-webfont.woff') format('woff');
font-weight: 100;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-extralight-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-extralight-webfont.woff') format('woff');
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-extralightitalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-extralightitalic-webfont.woff') format('woff');
font-weight: 200;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-light-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-light-webfont.woff') format('woff');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-lightitalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-lightitalic-webfont.woff') format('woff');
font-weight: 300;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-regular-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-regular-webfont.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-italic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-italic-webfont.woff') format('woff');
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-medium-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-medium-webfont.woff') format('woff');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-mediumitalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-mediumitalic-webfont.woff') format('woff');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-semibold-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-semibold-webfont.woff') format('woff');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-semibolditalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-semibolditalic-webfont.woff') format('woff');
font-weight: 600;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-bold-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-bold-webfont.woff') format('woff');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-bolditalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-bolditalic-webfont.woff') format('woff');
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-extrabold-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-extrabold-webfont.woff') format('woff');
font-weight: 800;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-extrabolditalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-extrabolditalic-webfont.woff') format('woff');
font-weight: 800;
font-style: italic;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-black-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-black-webfont.woff') format('woff');
font-weight: 900;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('/static/fonts/montserrat/montserrat-blackitalic-webfont.woff2') format('woff2'),
url('/static/fonts/montserrat/montserrat-blackitalic-webfont.woff') format('woff');
font-weight: 900;
font-style: italic;
}

View File

@ -18,6 +18,7 @@
<link rel="icon" href="{{ url_for('static', filename='images/base/favicon.svg') }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ url_for('static', filename='images/base/apple-touch-icon.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css') }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
</head>
@ -25,9 +26,9 @@
<body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<nav class="navbar navbar-expand-lg bg-light">
<nav class="navbar navbar-expand-lg bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('index') }}">
<a class="navbar-brand pb-2" href="{{ url_for('index') }}">
<img src="{{ url_for('static', filename='images/base/navbar-logo.svg') }}"
alt="Lumi2 Logo" style="max-height: 60px"
>
@ -39,14 +40,14 @@
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% if g.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('usermanager.user_list') }}">Users</a>
<a class="nav-link text-primary fw-bold fs-3" href="{{ url_for('usermanager.user_list') }}">Users</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('usermanager.group_list') }}">Groups</a>
<a class="nav-link text-primary fw-bold fs-3" href="{{ url_for('usermanager.group_list') }}">Groups</a>
</li>
{% endif%}
<li class="nav-item">
<a class="nav-link" href="#">About</a>
<a class="nav-link text-primary fs-3" href="#">About</a>
</li>
</ul>
{% if g.is_authenticated %}
@ -76,7 +77,7 @@
{% endfor %}
{% endif %}
{% endwith %}
<div class="container border rounded mt-3">
<div class="container border rounded my-3">
{% block content %}
{% endblock content %}
</div>

View File

@ -1,19 +1,19 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="row mt-4">
<div class="col text-center">
<h1>Create a new Group</h1>
<h1 class="display-3">Create a new Group</h1>
</div>
</div>
<div class="row align-items-center border rounded m-2">
<label for="groupNameInput" class="col-sm-2 col-form-label text-center m-2">Group Name</label>
<label for="groupNameInput" class="col-sm-2 col-form-label fw-bold text-center m-2">Group Name</label>
<input type="text" class="col-sm form-control m-2" id="groupNameInput">
<a class="col-sm-2 btn btn-secondary m-2" href="{{ url_for('usermanager.group_list') }}" role="button">Cancel</a>
<a class="col-sm-2 btn btn-outline-secondary m-2" href="{{ url_for('usermanager.group_list') }}" role="button">Cancel</a>
<button class="col-sm-2 btn btn-primary m-2" type="button" id="createGroupButton">Create Group</button>
</div>
<div class="row border rounded m-2">
<table class="table table-hover align-middle" id="tableMembers">
<table class="table align-middle" id="tableMembers">
<thead>
<tr>
<th class="text-center" scope="col" colspan="3">Members</th>
@ -28,8 +28,8 @@
</tbody>
</table>
</div>
<div class="row border rounded m-2">
<table class="table table-hover align-middle" id="tableNonMembers">
<div class="row border rounded mx-2 mb-2 mt-5">
<table class="table align-middle" id="tableNonMembers">
<thead>
<tr>
<th class="text-center" scope="col" colspan="3">Other Users</th>
@ -39,14 +39,16 @@
{% for user in users|sort %}
<tr class="userEntry text-center" id="{{ user.username }}">
<th scope="row">
<img src="{{ user.get_thumbnail_url() }}"
alt="Profile picture for user {{ user.username }}"
class="img-fluid rounded"
style="max-width: 50px"
>
<a href="{{ url_for('usermanager.user_view', username=user.username)}}">
<img src="{{ user.get_thumbnail_url() }}"
alt="Profile picture for user {{ user.username }}"
class="img-fluid rounded"
style="max-width: 50px"
>
</a>
</th>
<td>
<a href="{{ url_for('usermanager.user_view', username=user.username)}}">{{ user.username }}</a>
<a class="text-decoration-none fw-bold" href="{{ url_for('usermanager.user_view', username=user.username)}}">{{ user.username }}</a>
</td>
<td>
<button type="button" class="toggleMembershipButton btn btn-success">

View File

@ -1,12 +1,12 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="row mt-4">
<div class="col">
<h1 class="text-center">Editing group: {{ groupname }}</h1>
<h1 class="text-center display-4">Editing group: {{ groupname }}</h1>
</div>
</div>
<div class="text-center border-bottom pb-1 mb-1">
<div class="text-center border-bottom pb-3 mb-1">
<a class="btn btn-outline-danger"
href="{{ url_for('usermanager.group_delete', groupname=groupname) }}"
role="button"
@ -14,7 +14,7 @@
</div>
<div class="row">
<div class="col-sm border border-primary rounded m-2">
<table class="table table-hover align-middle" id="tableMembers">
<table class="table align-middle" id="tableMembers">
<thead>
<tr>
<th scope="col" colspan="3" class="text-center">{{ groupname }}</th>
@ -24,14 +24,16 @@
{% for user in members|sort %}
<tr class="userEntry text-center" id="{{ user.username }}">
<th scope="row">
<img src="{{ user.get_thumbnail_url() }}"
alt="Profile picture for user {{ user.username }}"
class="img-fluid rounded"
style="max-width: 50px"
>
<a href="{{ url_for('usermanager.user_view', username=user.username)}}">
<img src="{{ user.get_thumbnail_url() }}"
alt="Profile picture for user {{ user.username }}"
class="img-fluid rounded"
style="max-width: 50px"
>
</a>
</th>
<td>
<a href="{{ url_for('usermanager.user_view', username=user.username)}}">{{ user.username }}</a>
<a class="text-decoration-none fw-bold" href="{{ url_for('usermanager.user_view', username=user.username)}}">{{ user.username }}</a>
</td>
<td>
<button type="button" class="toggleMembershipButton btn btn-danger">
@ -44,7 +46,7 @@
</table>
</div>
<div class="col-sm border rounded m-2">
<table class="table table-hover align-middle" id="tableNonMembers">
<table class="table align-middle" id="tableNonMembers">
<thead>
<tr>
<th scope="col" colspan="3" class="text-center">Other Users</th>
@ -54,14 +56,16 @@
{% for user in non_members|sort %}
<tr class="userEntry text-center" id="{{ user.username }}">
<th scope="row">
<img src="{{ user.get_thumbnail_url() }}"
alt="Profile picture for user {{ user.username }}"
class="img-fluid rounded"
style="max-width: 50px"
>
<a href="{{ url_for('usermanager.user_view', username=user.username)}}">
<img src="{{ user.get_thumbnail_url() }}"
alt="Profile picture for user {{ user.username }}"
class="img-fluid rounded"
style="max-width: 50px"
>
</a>
</th>
<td>
<a href="{{ url_for('usermanager.user_view', username=user.username)}}">{{ user.username }}</a>
<a class="text-decoration-none fw-bold" href="{{ url_for('usermanager.user_view', username=user.username)}}">{{ user.username }}</a>
</td>
<td>
<button type="button" class="toggleMembershipButton btn btn-success">

View File

@ -1,10 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<div class="text-center border-bottom mb-1">
<h1>All groups</h1>
<div class="text-center mb-2">
<h1 class="display-1">Groups</h1>
</div>
<div class="text-center border-bottom pb-1 mb-1">
<div class="text-center border-bottom pb-4 mb-1">
<a class="btn btn-primary"
href="{{ url_for('usermanager.group_create') }}"
role="button"
@ -12,7 +12,7 @@
</div>
{% if groups %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Group Name</th>
@ -21,11 +21,11 @@
</thead>
<tbody>
{% for group in groups | sort %}
<tr>
<tr class="clickable" onclick="window.location='{{ url_for('usermanager.group_update', groupname=group.groupname) }}'" style="cursor: pointer">
<th scope="row">
<a href="{{ url_for('usermanager.group_update', groupname=group.groupname) }}">{{ group.groupname }}</a>
<a class="text-decoration-none fw-bold fs-4" href="{{ url_for('usermanager.group_update', groupname=group.groupname) }}">{{ group.groupname }}</a>
</th>
<td class="align-middle">
<td class="align-middle fs-5">
{{ group.members|length }}
</td>
</tr>

View File

@ -1,7 +1,6 @@
{% extends 'base.html' %}
{% block content %}
<h1 class="text-center">Welcome</h1>
<div class="row justify-content-md-center">
<img src="{{ url_for('static', filename='images/base/navbar-logo.svg') }}"
alt="Logo for lumi2"
@ -9,6 +8,7 @@
style="max-width: 400px"
>
</div>
<h1 class="text-center display-1">Welcome</h1>
<div class="row justify-content-md-centermt-4">
<p class="fs-3 text-secondary text-center "><i class="bi-cone-striped"></i> This site is still under construction <i class="bi-cone-striped"></i></p>
<p class="fs-3">With Lumi2 you can easily manage the users and user-groups on your LDAP server.</p>

View File

@ -1,9 +1,9 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="row mt-4">
<div class="col">
<h1 class="text-center">{{ heading }}</h1>
<h1 class="text-center display-3">{{ heading }}</h1>
</div>
</div>
<form method="post" enctype="multipart/form-data">

View File

@ -1,10 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<div class="text-center border-bottom mb-1">
<h1>All users</h1>
<div class="text-center m-2">
<h1 class="display-1">Users</h1>
</div>
<div class="text-center border-bottom pb-1 mb-1">
<div class="text-center border-bottom pb-4 mb-1">
<a class="btn btn-primary"
href="{{ url_for('usermanager.user_create') }}"
role="button"
@ -12,7 +12,7 @@
</div>
{% if users %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Picture</th>
@ -25,7 +25,7 @@
</thead>
<tbody>
{% for user in users | sort %}
<tr>
<tr class="clickable" onclick="window.location='{{ url_for('usermanager.user_view', username=user.username) }}'" style="cursor: pointer">
<th scope="row">
<img src="{{ user.get_thumbnail_url() }}"
alt="profile picture for user {{ user.username }}"
@ -34,7 +34,7 @@
>
</th>
<td class="align-middle">
<a href="{{ url_for('usermanager.user_view', username=user.username) }}">{{ user.username }}</a>
<a class="text-decoration-none fw-bold" href="{{ url_for('usermanager.user_view', username=user.username) }}">{{ user.username }}</a>
</td>
<td class="align-middle">{{ user.last_name }}</td>
<td class="align-middle">{{ user.first_name }}</td>

View File

@ -20,7 +20,7 @@
<a class="btn btn-primary"
href="{{ url_for('usermanager.user_update', username=user.username) }}"
role="button"><i class="bi-person-gear"></i> Edit</a>
<a class="btn btn-danger"
<a class="btn btn-outline-danger"
href="{{ url_for('usermanager.user_delete', username=user.username) }}"
role="button"><i class="bi-person-slash"></i> Delete</a>
</div>

41
scss/bootstrap.scss vendored
View File

@ -1,3 +1,42 @@
//$primary: #DD5533;
// Colors
$body-bg: #FCF7E3;
$body-color: #3A3533;
$link-color: #3890a9;
$primary: #72BAB0;
$secondary: #C8C395;
$success: #56BB80;
$info: #799F93;
$warning: #DBB263;
$danger: #B9413C;
$light: #FCFAF3;
$dark: #234350;
// Fonts
$font-family-base: Montserrat;
$font-weight-lighter: 300;
$font-weight-light: 400;
$font-weight-normal: 500;
$font-weight-semibold: 600;
$font-weight-bold: 700;
$font-weight-bolder: 800;
$display-font-weight: 500;
// Borders
$border-width: 2px;
$border-widths: (
1: 2px,
2: 3px,
3: 4px,
4: 5px,
5: 6px
);
$border-color: #DEDABF;
// Forms
$input-border-color: #A49E68;
@import "../node_modules/bootstrap/scss/bootstrap";