Skip to content

Commit ac585c7

Browse files
committed
feat: Changed admin panel style theme
- Added a template of admin html files - Added a css file contains the style of the navbar - Changed the requirements of flask-admin in order to support bootstrap4
1 parent 07cafa7 commit ac585c7

File tree

6 files changed

+329
-2
lines changed

6 files changed

+329
-2
lines changed

lms/lmsweb/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,6 @@ class AdminCommentTextView(AdminModelView):
6969
admin = Admin(
7070
webapp,
7171
name='LMS',
72-
template_mode='bootstrap3',
72+
template_mode='bootstrap4',
7373
index_view=MyAdminIndexView(), # NOQA
7474
)

lms/lmsweb/config.py.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ MAILGUN_API_KEY = os.getenv('MAILGUN_API_KEY')
99
MAILGUN_DOMAIN = os.getenv('MAILGUN_DOMAIN', 'mail.pythonic.guru')
1010
SERVER_ADDRESS = os.getenv('SERVER_ADDRESS', '127.0.0.1:5000')
1111

12+
# ADMIN PANEL
13+
FLASK_ADMIN_FLUID_LAYOUT = True
14+
1215
# SESSION_COOKIE_SECURE = True
1316
SESSION_COOKIE_HTTPONLY = True
1417
SESSION_COOKIE_SAMESITE = 'Lax'

lms/static/admin.css

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
@import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";
2+
3+
4+
body {
5+
font-family: 'Poppins', sans-serif;
6+
background: #fafafa;
7+
}
8+
9+
p {
10+
font-family: 'Poppins', sans-serif;
11+
font-size: 1.1em;
12+
font-weight: 300;
13+
line-height: 1.7em;
14+
color: #999;
15+
}
16+
17+
a, a:hover, a:focus {
18+
color: inherit;
19+
text-decoration: none;
20+
transition: all 0.3s;
21+
}
22+
23+
.navbar {
24+
padding: 15px 10px;
25+
background: #fff;
26+
border: none;
27+
border-radius: 0;
28+
margin-bottom: 40px;
29+
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
30+
}
31+
32+
.navbar-btn {
33+
box-shadow: none;
34+
outline: none !important;
35+
border: none;
36+
}
37+
38+
.line {
39+
width: 100%;
40+
height: 1px;
41+
border-bottom: 1px dashed #ddd;
42+
margin: 40px 0;
43+
}
44+
45+
/* ---------------------------------------------------
46+
SIDEBAR STYLE
47+
----------------------------------------------------- */
48+
49+
.wrapper {
50+
display: flex;
51+
width: 100%;
52+
align-items: stretch;
53+
perspective: 1500px;
54+
}
55+
56+
57+
#sidebar {
58+
min-width: 250px;
59+
max-width: 250px;
60+
background: #0d6efd;
61+
color: #fff;
62+
transition: all 0.6s cubic-bezier(0.945, 0.020, 0.270, 0.665);
63+
transform-origin: bottom left;
64+
}
65+
66+
#sidebar.active {
67+
margin-left: -250px;
68+
transform: rotateY(100deg);
69+
}
70+
71+
#sidebar .sidebar-header {
72+
padding: 20px;
73+
background: #0d6efd;
74+
}
75+
76+
#sidebar ul.components {
77+
padding: 20px 0;
78+
border-bottom: 1px solid #47748b;
79+
}
80+
81+
#sidebar ul p {
82+
color: #fff;
83+
padding: 10px;
84+
}
85+
86+
#sidebar ul li a {
87+
padding: 10px;
88+
font-size: 1.1em;
89+
display: block;
90+
}
91+
#sidebar ul li a:hover {
92+
color: #0653c5;
93+
background: #fff;
94+
}
95+
96+
#sidebar ul li.active > a, a[aria-expanded="true"] {
97+
color: #fff;
98+
background: #0653c5;
99+
}
100+
101+
ul ul a {
102+
font-size: 0.9em !important;
103+
padding-left: 30px !important;
104+
background: #0d6efd;
105+
}
106+
107+
ul.CTAs {
108+
padding: 20px;
109+
}
110+
111+
ul.CTAs a {
112+
text-align: center;
113+
font-size: 0.9em !important;
114+
display: block;
115+
border-radius: 5px;
116+
margin-bottom: 5px;
117+
}
118+
119+
120+
/* ---------------------------------------------------
121+
CONTENT STYLE
122+
----------------------------------------------------- */
123+
#content {
124+
width: 100%;
125+
padding: 20px;
126+
min-height: 100vh;
127+
transition: all 0.3s;
128+
}
129+
130+
#sidebarCollapse {
131+
width: 40px;
132+
height: 40px;
133+
background: #f5f5f5;
134+
cursor: pointer;
135+
}
136+
137+
#sidebarCollapse span {
138+
width: 80%;
139+
height: 2px;
140+
margin: 0 auto;
141+
display: block;
142+
background: #555;
143+
transition: all 0.8s cubic-bezier(0.810, -0.330, 0.345, 1.375);
144+
transition-delay: 0.2s;
145+
}
146+
147+
#sidebarCollapse span:first-of-type {
148+
transform: rotate(45deg) translate(2px, 2px);
149+
}
150+
#sidebarCollapse span:nth-of-type(2) {
151+
opacity: 0;
152+
}
153+
#sidebarCollapse span:last-of-type {
154+
transform: rotate(-45deg) translate(1px, -1px);
155+
}
156+
157+
158+
#sidebarCollapse.active span {
159+
transform: none;
160+
opacity: 1;
161+
margin: 5px auto;
162+
}
163+
164+
165+
/* ---------------------------------------------------
166+
MEDIAQUERIES
167+
----------------------------------------------------- */
168+
@media (max-width: 768px) {
169+
#sidebar {
170+
margin-left: -250px;
171+
transform: rotateY(90deg);
172+
}
173+
#sidebar.active {
174+
margin-left: 0;
175+
transform: none;
176+
}
177+
#sidebarCollapse span:first-of-type,
178+
#sidebarCollapse span:nth-of-type(2),
179+
#sidebarCollapse span:last-of-type {
180+
transform: none;
181+
opacity: 1;
182+
margin: 5px auto;
183+
}
184+
#sidebarCollapse.active span {
185+
margin: 0 auto;
186+
}
187+
#sidebarCollapse.active span:first-of-type {
188+
transform: rotate(45deg) translate(2px, 2px);
189+
}
190+
#sidebarCollapse.active span:nth-of-type(2) {
191+
opacity: 0;
192+
}
193+
#sidebarCollapse.active span:last-of-type {
194+
transform: rotate(-45deg) translate(1px, -1px);
195+
}
196+
197+
}

lms/templates/admin/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{% extends 'admin/master.html' %}
2+
{% block head_css %}
3+
{{ super() }}
4+
{% endblock head_css %}
5+
{% block body %}
6+
{% endblock %}

lms/templates/admin/master.html

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
{% import 'admin/layout.html' as layout with context -%}
2+
{% import 'admin/static.html' as admin_static with context %}
3+
<!DOCTYPE html>
4+
<html>
5+
<head>
6+
<title>{% block title %}{% if admin_view.category %}{{ admin_view.category }} - {% endif %}{{ admin_view.name }} - {{ admin_view.admin.name }}{% endblock %}</title>
7+
{% block head_meta %}
8+
<meta charset="UTF-8">
9+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
10+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
11+
<meta name="description" content="">
12+
<meta name="author" content="">
13+
{% endblock %}
14+
{% block head_css %}
15+
<link href="{{ admin_static.url(filename='bootstrap/bootstrap4/swatch/{swatch}/bootstrap.min.css'.format(swatch=config.get('FLASK_ADMIN_SWATCH', 'default')), v='4.2.1') }}"
16+
rel="stylesheet">
17+
{% if config.get('FLASK_ADMIN_SWATCH', 'default') == 'default' %}
18+
<link href="{{ admin_static.url(filename='bootstrap/bootstrap4/css/bootstrap.min.css', v='4.2.1') }}" rel="stylesheet">
19+
{% endif %}
20+
<link href="{{ admin_static.url(filename='admin/css/bootstrap4/admin.css', v='1.1.1') }}" rel="stylesheet">
21+
<link href="{{ admin_static.url(filename='bootstrap/bootstrap4/css/font-awesome.min.css', v='4.7.0') }}" rel="stylesheet">
22+
<link rel="stylesheet" href="{{ url_for('static', filename='admin.css') }}">
23+
{% if admin_view.extra_css %}
24+
{% for css_url in admin_view.extra_css %}
25+
<link href="{{ css_url }}" rel="stylesheet">
26+
{% endfor %}
27+
{% endif %}
28+
<style>
29+
.hide {
30+
display: none;
31+
}
32+
</style>
33+
{% endblock %}
34+
{% block head %}
35+
{% endblock %}
36+
{% block head_tail %}
37+
{% endblock %}
38+
</head>
39+
<body>
40+
<div class="wrapper">
41+
{% block page_body %}
42+
<nav id="sidebar">
43+
<div class="sidebar-header">
44+
{% block brand %}
45+
<a class="navbar-brand" href="{{ admin_view.admin.url }}">{{ admin_view.admin.name }}</a>
46+
{% endblock %}
47+
</div>
48+
49+
{% block main_menu %}
50+
<ul class="list-unstyled components">
51+
{{ layout.menu() }}
52+
</ul>
53+
{% endblock %}
54+
</nav>
55+
56+
<div id="content">
57+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
58+
<div class="container-fluid">
59+
60+
<button type="button" id="sidebarCollapse" class="navbar-btn">
61+
<span></span>
62+
<span></span>
63+
<span></span>
64+
</button>
65+
<button class="btn btn-dark d-inline-block d-lg-none ml-auto" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
66+
<i class="fas fa-align-justify"></i>
67+
</button>
68+
69+
<div class="collapse navbar-collapse" id="navbarSupportedContent">
70+
{% block menu_links %}
71+
<ul class="nav navbar-nav navbar-right">
72+
{{ layout.menu_links() }}
73+
</ul>
74+
{% endblock %}
75+
</div>
76+
</div>
77+
</nav>
78+
{% block access_control %}
79+
{% endblock %}
80+
{% block messages %}
81+
{{ layout.messages() }}
82+
{% endblock %}
83+
84+
{# store the jinja2 context for form_rules rendering logic #}
85+
{% set render_ctx = h.resolve_ctx() %}
86+
87+
{% block body %}{% endblock %}
88+
</div>
89+
90+
{% endblock %}
91+
</div>
92+
93+
{% block tail_js %}
94+
<script src="{{ admin_static.url(filename='vendor/jquery.min.js', v='2.1.4') }}" type="text/javascript"></script>
95+
<script src="{{ admin_static.url(filename='bootstrap/bootstrap4/js/popper.min.js') }}" type="text/javascript"></script>
96+
<script src="{{ admin_static.url(filename='bootstrap/bootstrap4/js/bootstrap.min.js', v='4.2.1') }}"
97+
type="text/javascript"></script>
98+
<script src="{{ admin_static.url(filename='vendor/moment.min.js', v='2.9.0') }}" type="text/javascript"></script>
99+
<script src="{{ admin_static.url(filename='vendor/bootstrap4/util.js', v='4.3.1') }}" type="text/javascript"></script>
100+
<script src="{{ admin_static.url(filename='vendor/select2/select2.min.js', v='4.2.1') }}"
101+
type="text/javascript"></script>
102+
<script src="{{ admin_static.url(filename='admin/js/helpers.js', v='1.0.0') }}" type="text/javascript"></script>
103+
<script type="text/javascript">
104+
$(document).ready(function () {
105+
$('#sidebarCollapse').on('click', function () {
106+
$('#sidebar').toggleClass('active');
107+
$(this).toggleClass('active');
108+
});
109+
});
110+
</script>
111+
{% if admin_view.extra_js %}
112+
{% for js_url in admin_view.extra_js %}
113+
<script src="{{ js_url }}" type="text/javascript"></script>
114+
{% endfor %}
115+
{% endif %}
116+
{% endblock %}
117+
118+
{% block tail %}
119+
{% endblock %}
120+
</body>
121+
</html>

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ flake8-quotes==3.2.0
3838
flake8-tidy-imports==4.1.0
3939
flake8-todo==0.7
4040
flake8==3.8.3
41-
Flask-Admin==1.5.6
41+
Flask-Admin==1.5.8
4242
Flask-Babel==2.0.0
4343
Flask-Limiter==1.4
4444
git+git://github.com/maxcountryman/flask-login@e3d8079#egg=flask-login

0 commit comments

Comments
 (0)