From ac585c735f0522c8537c47f50cc54d7dc2b5e6b1 Mon Sep 17 00:00:00 2001 From: Or Ronai Date: Thu, 9 Sep 2021 15:15:02 +0300 Subject: [PATCH] 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 --- lms/lmsweb/admin.py | 2 +- lms/lmsweb/config.py.example | 3 + lms/static/admin.css | 197 ++++++++++++++++++++++++++++++++ lms/templates/admin/index.html | 6 + lms/templates/admin/master.html | 121 ++++++++++++++++++++ requirements.txt | 2 +- 6 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 lms/static/admin.css create mode 100644 lms/templates/admin/index.html create mode 100644 lms/templates/admin/master.html diff --git a/lms/lmsweb/admin.py b/lms/lmsweb/admin.py index 79d8cbb8..6b2930b8 100644 --- a/lms/lmsweb/admin.py +++ b/lms/lmsweb/admin.py @@ -69,6 +69,6 @@ class AdminCommentTextView(AdminModelView): admin = Admin( webapp, name='LMS', - template_mode='bootstrap3', + template_mode='bootstrap4', index_view=MyAdminIndexView(), # NOQA ) diff --git a/lms/lmsweb/config.py.example b/lms/lmsweb/config.py.example index 0bf3aca7..1fab4072 100644 --- a/lms/lmsweb/config.py.example +++ b/lms/lmsweb/config.py.example @@ -9,6 +9,9 @@ MAILGUN_API_KEY = os.getenv('MAILGUN_API_KEY') MAILGUN_DOMAIN = os.getenv('MAILGUN_DOMAIN', 'mail.pythonic.guru') SERVER_ADDRESS = os.getenv('SERVER_ADDRESS', '127.0.0.1:5000') +# ADMIN PANEL +FLASK_ADMIN_FLUID_LAYOUT = True + # SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Lax' diff --git a/lms/static/admin.css b/lms/static/admin.css new file mode 100644 index 00000000..4dfb433c --- /dev/null +++ b/lms/static/admin.css @@ -0,0 +1,197 @@ +@import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700"; + + +body { + font-family: 'Poppins', sans-serif; + background: #fafafa; +} + +p { + font-family: 'Poppins', sans-serif; + font-size: 1.1em; + font-weight: 300; + line-height: 1.7em; + color: #999; +} + +a, a:hover, a:focus { + color: inherit; + text-decoration: none; + transition: all 0.3s; +} + +.navbar { + padding: 15px 10px; + background: #fff; + border: none; + border-radius: 0; + margin-bottom: 40px; + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); +} + +.navbar-btn { + box-shadow: none; + outline: none !important; + border: none; +} + +.line { + width: 100%; + height: 1px; + border-bottom: 1px dashed #ddd; + margin: 40px 0; +} + +/* --------------------------------------------------- + SIDEBAR STYLE +----------------------------------------------------- */ + +.wrapper { + display: flex; + width: 100%; + align-items: stretch; + perspective: 1500px; +} + + +#sidebar { + min-width: 250px; + max-width: 250px; + background: #0d6efd; + color: #fff; + transition: all 0.6s cubic-bezier(0.945, 0.020, 0.270, 0.665); + transform-origin: bottom left; +} + +#sidebar.active { + margin-left: -250px; + transform: rotateY(100deg); +} + +#sidebar .sidebar-header { + padding: 20px; + background: #0d6efd; +} + +#sidebar ul.components { + padding: 20px 0; + border-bottom: 1px solid #47748b; +} + +#sidebar ul p { + color: #fff; + padding: 10px; +} + +#sidebar ul li a { + padding: 10px; + font-size: 1.1em; + display: block; +} +#sidebar ul li a:hover { + color: #0653c5; + background: #fff; +} + +#sidebar ul li.active > a, a[aria-expanded="true"] { + color: #fff; + background: #0653c5; +} + +ul ul a { + font-size: 0.9em !important; + padding-left: 30px !important; + background: #0d6efd; +} + +ul.CTAs { + padding: 20px; +} + +ul.CTAs a { + text-align: center; + font-size: 0.9em !important; + display: block; + border-radius: 5px; + margin-bottom: 5px; +} + + +/* --------------------------------------------------- + CONTENT STYLE +----------------------------------------------------- */ +#content { + width: 100%; + padding: 20px; + min-height: 100vh; + transition: all 0.3s; +} + +#sidebarCollapse { + width: 40px; + height: 40px; + background: #f5f5f5; + cursor: pointer; +} + +#sidebarCollapse span { + width: 80%; + height: 2px; + margin: 0 auto; + display: block; + background: #555; + transition: all 0.8s cubic-bezier(0.810, -0.330, 0.345, 1.375); + transition-delay: 0.2s; +} + +#sidebarCollapse span:first-of-type { + transform: rotate(45deg) translate(2px, 2px); +} +#sidebarCollapse span:nth-of-type(2) { + opacity: 0; +} +#sidebarCollapse span:last-of-type { + transform: rotate(-45deg) translate(1px, -1px); +} + + +#sidebarCollapse.active span { + transform: none; + opacity: 1; + margin: 5px auto; +} + + +/* --------------------------------------------------- + MEDIAQUERIES +----------------------------------------------------- */ +@media (max-width: 768px) { + #sidebar { + margin-left: -250px; + transform: rotateY(90deg); + } + #sidebar.active { + margin-left: 0; + transform: none; + } + #sidebarCollapse span:first-of-type, + #sidebarCollapse span:nth-of-type(2), + #sidebarCollapse span:last-of-type { + transform: none; + opacity: 1; + margin: 5px auto; + } + #sidebarCollapse.active span { + margin: 0 auto; + } + #sidebarCollapse.active span:first-of-type { + transform: rotate(45deg) translate(2px, 2px); + } + #sidebarCollapse.active span:nth-of-type(2) { + opacity: 0; + } + #sidebarCollapse.active span:last-of-type { + transform: rotate(-45deg) translate(1px, -1px); + } + +} diff --git a/lms/templates/admin/index.html b/lms/templates/admin/index.html new file mode 100644 index 00000000..d88e3fe0 --- /dev/null +++ b/lms/templates/admin/index.html @@ -0,0 +1,6 @@ +{% extends 'admin/master.html' %} +{% block head_css %} + {{ super() }} +{% endblock head_css %} +{% block body %} +{% endblock %} diff --git a/lms/templates/admin/master.html b/lms/templates/admin/master.html new file mode 100644 index 00000000..36d6d162 --- /dev/null +++ b/lms/templates/admin/master.html @@ -0,0 +1,121 @@ +{% import 'admin/layout.html' as layout with context -%} +{% import 'admin/static.html' as admin_static with context %} + + + + {% block title %}{% if admin_view.category %}{{ admin_view.category }} - {% endif %}{{ admin_view.name }} - {{ admin_view.admin.name }}{% endblock %} + {% block head_meta %} + + + + + + {% endblock %} + {% block head_css %} + + {% if config.get('FLASK_ADMIN_SWATCH', 'default') == 'default' %} + + {% endif %} + + + + {% if admin_view.extra_css %} + {% for css_url in admin_view.extra_css %} + + {% endfor %} + {% endif %} + + {% endblock %} + {% block head %} + {% endblock %} + {% block head_tail %} + {% endblock %} + + +
+ {% block page_body %} + + +
+ + {% block access_control %} + {% endblock %} + {% block messages %} + {{ layout.messages() }} + {% endblock %} + + {# store the jinja2 context for form_rules rendering logic #} + {% set render_ctx = h.resolve_ctx() %} + + {% block body %}{% endblock %} +
+ + {% endblock %} +
+ +{% block tail_js %} + + + + + + + + + {% if admin_view.extra_js %} + {% for js_url in admin_view.extra_js %} + + {% endfor %} + {% endif %} +{% endblock %} + + {% block tail %} + {% endblock %} + + diff --git a/requirements.txt b/requirements.txt index 86f6b8c7..9b9990eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,7 @@ flake8-quotes==3.2.0 flake8-tidy-imports==4.1.0 flake8-todo==0.7 flake8==3.8.3 -Flask-Admin==1.5.6 +Flask-Admin==1.5.8 Flask-Babel==2.0.0 Flask-Limiter==1.4 git+git://github.com/maxcountryman/flask-login@e3d8079#egg=flask-login