From 2d999fe8da529328296ecd0c7e094bc15a61f4e9 Mon Sep 17 00:00:00 2001 From: Abdur-Rahmaan Janhangeer Date: Tue, 31 Jan 2023 14:45:45 +0400 Subject: [PATCH 1/4] fix: mv theme helpers to helper file --- .dockerignore | 38 - .gitignore | 72 +- .pre-commit-config.yaml | 49 +- CODE_OF_CONDUCT.md | 76 - CONTRIBUTING.md | 47 - LICENSE | 20 - MANIFEST.in | 8 + Makefile | 113 -- README.md | 405 +--- SECURITY.md | 27 - cookiecutter-config-file.yml | 13 - dev_requirements.txt | 12 + docs/conf.py | 3 +- docs/index.rst | 2 +- poetry.lock | 1767 ----------------- pyproject.toml | 152 -- pytest.ini | 3 + {src => pythoncms}/.test.prod.env | 0 pythoncms/CHANGELOG.md | 242 +++ {src => pythoncms}/__init__.py | 0 pythoncms/app.py | 266 +++ .../autoapp.py.example | 4 + {src => pythoncms}/cli.py | 11 +- {src => pythoncms}/config.py | 16 + {src => pythoncms}/config_demo.json | 0 {src => pythoncms}/conftest.py | 58 +- {src => pythoncms}/init.py | 17 +- {src => pythoncms}/manage.py | 0 pythoncms/migrations/README | 1 + pythoncms/migrations/alembic.ini | 50 + pythoncms/migrations/env.py | 99 + pythoncms/migrations/script.py.mako | 24 + .../migrations/versions/cb42bf1aaf17_.py | 84 + {src => pythoncms}/modules/__init__.py | 0 .../box__default/appadmin}/__init__.py | 0 .../modules/box__default/appadmin/admin.py | 9 +- .../modules/box__default/appadmin/info.json | 1 + .../modules/box__default/appadmin/models.py | 0 .../appadmin/templates/appadmin/add.html | 0 .../templates/appadmin/blocks/sidebar.html | 0 .../appadmin/templates/appadmin/edit.html | 0 .../appadmin/templates/appadmin/index.html | 0 .../appadmin/templates/appadmin/roles.html | 0 .../box__default/appadmin/tests/test_admin.py | 405 ++++ .../appadmin/tests/test_models.py | 0 .../modules/box__default/appadmin/view.py | 45 +- .../modules/box__default/auth/decorators.py | 0 .../modules/box__default/auth/forms.py | 0 .../modules/box__default/auth/info.json | 1 + .../modules/box__default/auth/models.py | 5 +- .../box__default/auth/static/style.css | 0 .../templates/auth/blocks/login_form.html | 0 .../templates/auth/blocks/register_form.html | 0 .../templates/auth/emails/activate_user.html | 0 .../templates/auth/emails/activate_user.txt | 0 .../auth/templates/auth/login.html | 0 .../auth/templates/auth/register.html | 0 .../auth/templates/auth/shop_login.html | 0 .../auth/templates/auth/unconfirmed.html | 0 .../box__default/auth/tests/conftest.py | 0 .../box__default/auth/tests/factories.py | 3 +- .../auth/tests/test_auth_forms.py | 0 .../auth/tests/test_auth_functional.py | 288 +++ .../auth/tests/test_auth_models.py | 175 +- .../modules/box__default/auth/upload.py | 0 .../modules/box__default/auth/view.py | 32 +- pythoncms/modules/box__default/base/info.json | 7 + .../templates/base/blocks/default_styles.html | 0 .../base/blocks/flashed_messages.html | 0 .../base/templates/base/blocks/footer.html | 0 .../base/templates/base/blocks/macros.html | 0 .../base/templates/base/blocks/resources.html | 0 .../base/templates/base/main_base.html | 0 .../base/templates/base/module_base.html | 0 .../base/templates/base/nav_base.html | 0 pythoncms/modules/box__default/base/view.py | 32 + .../modules/box__default/box_info.json | 0 .../modules/box__default/dashboard/info.json | 7 + .../dashboard/templates/dashboard/index.html | 0 .../dashboard/templates/dashboard/nav.html | 0 .../dashboard/tests/test_dashboard.py | 46 + .../modules/box__default/dashboard/view.py | 16 +- .../modules/box__default/i18n}/forms.py | 0 pythoncms/modules/box__default/i18n/global.py | 22 + .../modules/box__default/i18n/helpers.py | 15 + pythoncms/modules/box__default/i18n/info.json | 12 + pythoncms/modules/box__default/i18n/models.py | 9 + .../i18n/templates/i18n}/blocks/sidebar.html | 0 .../i18n/templates/i18n/dashboard.html | 19 + .../i18n/tests/test_i18n_functional.py | 1 + .../i18n/tests/test_i18n_models.py | 1 + pythoncms/modules/box__default/i18n/view.py | 46 + .../modules/box__default}/page/forms.py | 3 + .../modules/box__default}/page/info.json | 0 pythoncms/modules/box__default/page/models.py | 73 + .../page/templates/page/all_pages.html | 21 +- .../page/templates/page/blocks/sidebar.html | 4 +- .../page/templates/page/dashboard.html | 8 + .../page/templates/page/dashboard_edit.html | 0 .../page/templates/page/view_page.html | 15 + .../templates/page/view_page_dashboard.html | 109 + pythoncms/modules/box__default/page/view.py | 119 ++ .../box__default/settings}/__init__.py | 0 .../modules/box__default/settings/helpers.py | 0 .../modules/box__default/settings/info.json | 3 +- .../modules/box__default/settings/models.py | 0 .../settings/templates/settings/edit.html | 0 .../settings/templates/settings/index.html | 0 .../settings/templates/settings/nav.html | 0 .../modules/box__default/settings/upload.py | 0 .../modules/box__default/settings/view.py | 0 .../modules/box__default/theme}/forms.py | 0 .../modules/box__default/theme/global.py | 10 + .../modules/box__default/theme/helper.py | 11 - .../modules/box__default/theme/info.json | 0 .../modules/box__default/theme/models.py | 0 .../theme/templates/theme/blocks/sidebar.html | 0 .../theme/templates/theme/index.html | 0 .../modules/box__default/theme/view.py | 3 +- .../modules/resource}/forms.py | 0 pythoncms/modules/resource/info.json | 12 + {src => pythoncms}/modules/resource/models.py | 0 .../templates/resource}/blocks/sidebar.html | 0 {src => pythoncms}/modules/resource/view.py | 0 .../modules/www/forms.py | 0 pythoncms/modules/www/global.py | 5 + {src => pythoncms}/modules/www/info.json | 0 {src => pythoncms}/modules/www/models.py | 0 .../www/templates/www/blocks/sidebar.html | 0 .../modules/www/templates/www/index.html | 13 + {src => pythoncms}/modules/www/view.py | 36 +- {src => pythoncms}/shopyo_admin.py | 0 .../static/bootstrap-grid.min.css | 0 .../static/bootstrap-reboot.min.css | 0 .../static/bootstrap.bundle.min.js | 0 {src => pythoncms}/static/bootstrap.min.css | 0 {src => pythoncms}/static/box.svg | 0 {src => pythoncms}/static/css/b4vtabs.min.css | 0 .../static/css/simple_sidebar.css | 0 .../static/default/default_product.jpg | Bin .../static/default/default_subcategory.jpg | Bin {src => pythoncms}/static/favicon.ico | Bin .../static/fontawesome/LICENSE.txt | 0 .../static/fontawesome/css/all.css | 0 .../static/fontawesome/css/all.min.css | 0 .../static/fontawesome/css/brands.css | 0 .../static/fontawesome/css/brands.min.css | 0 .../static/fontawesome/css/fontawesome.css | 0 .../fontawesome/css/fontawesome.min.css | 0 .../static/fontawesome/css/regular.css | 0 .../static/fontawesome/css/regular.min.css | 0 .../static/fontawesome/css/solid.css | 0 .../static/fontawesome/css/solid.min.css | 0 .../static/fontawesome/css/svg-with-js.css | 0 .../fontawesome/css/svg-with-js.min.css | 0 .../static/fontawesome/css/v4-shims.css | 0 .../static/fontawesome/css/v4-shims.min.css | 0 .../fontawesome/webfonts/fa-brands-400.eot | Bin .../fontawesome/webfonts/fa-brands-400.svg | 0 .../fontawesome/webfonts/fa-brands-400.ttf | Bin .../fontawesome/webfonts/fa-brands-400.woff | Bin .../fontawesome/webfonts/fa-brands-400.woff2 | Bin .../fontawesome/webfonts/fa-regular-400.eot | Bin .../fontawesome/webfonts/fa-regular-400.svg | 0 .../fontawesome/webfonts/fa-regular-400.ttf | Bin .../fontawesome/webfonts/fa-regular-400.woff | Bin .../fontawesome/webfonts/fa-regular-400.woff2 | Bin .../fontawesome/webfonts/fa-solid-900.eot | Bin .../fontawesome/webfonts/fa-solid-900.svg | 0 .../fontawesome/webfonts/fa-solid-900.ttf | Bin .../fontawesome/webfonts/fa-solid-900.woff | Bin .../fontawesome/webfonts/fa-solid-900.woff2 | Bin {src => pythoncms}/static/jquery_3.2.1.min.js | 0 {src => pythoncms}/static/js/python.js | 0 .../modules/box__default/auth/style.css | 7 + {src => pythoncms}/static/shopyo.png | Bin {src => pythoncms}/static/shopyo.svg | 0 .../static/themes/back/boogle/info.json | 0 .../static/themes/back/boogle/styles.css | 0 .../static/themes/back/mistrello/info.json | 0 .../static/themes/back/mistrello/styles.css | 0 .../static/themes/front/blogus/index.html | 0 .../static/themes/front/blogus/info.json | 0 .../themes/front/blogus/render_demo.html | 0 .../themes/front/blogus/sections/footer.html | 0 .../themes/front/blogus/sections/nav.html | 0 .../front/blogus/sections/resources.html | 0 .../static/themes/front/blogus/styles.css | 0 {src => pythoncms}/tests/conftest.py | 3 +- pythoncms/tests/test_configs.py | 57 + pythoncms/tests/test_dunder_main.py | 21 + pythoncms/tests/test_manage.py | 8 + src/wsgi.py => pythoncms/wsgi.py.example | 1 + requirements.txt | 11 +- setup.cfg | 4 - setup.py | 84 + src/app.py | 182 -- .../box__bizhelp/appointment/info.json | 11 - .../box__bizhelp/appointment/models.py | 10 - .../templates/appointment/add.html | 52 - .../templates/appointment/blocks/sidebar.html | 23 - .../templates/appointment/edit.html | 43 - .../templates/appointment/index.html | 100 - .../templates/appointment/lookup.html | 140 -- src/modules/box__bizhelp/appointment/view.py | 142 -- src/modules/box__bizhelp/box_info.json | 9 - src/modules/box__bizhelp/contact/forms.py | 29 - src/modules/box__bizhelp/contact/global.py | 8 - src/modules/box__bizhelp/contact/info.json | 12 - src/modules/box__bizhelp/contact/models.py | 24 - .../templates/contact/blocks/sidebar.html | 13 - .../templates/contact/contact_form.html | 52 - .../contact/templates/contact/dashboard.html | 60 - .../contact/tests/test_contact.py | 100 - src/modules/box__bizhelp/contact/view.py | 59 - src/modules/box__bizhelp/page/models.py | 24 - .../page/templates/page/view_page.html | 31 - src/modules/box__bizhelp/page/view.py | 81 - src/modules/box__bizhelp/people/info.json | 11 - src/modules/box__bizhelp/people/models.py | 20 - .../people/templates/people/add.html | 141 -- .../templates/people/blocks/sidebar.html | 24 - .../people/templates/people/edit.html | 143 -- .../people/templates/people/index.html | 107 - .../people/templates/people/lookup.html | 127 -- src/modules/box__bizhelp/people/view.py | 225 --- .../box__default/appadmin/tests/test_admin.py | 366 ---- src/modules/box__default/auth/email.py | 75 - .../auth/tests/test_auth_functional.py | 286 --- .../box__default/auth/tests/test_email.py | 92 - src/modules/box__default/base/info.json | 6 - src/modules/box__default/base/view.py | 17 - .../dashboard/tests/test_dashboard.py | 46 - src/modules/resource/info.json | 12 - src/modules/www/templates/www/index.html | 3 - src/tests/test_configs.py | 57 - tests/test_example/test_hello.py | 6 - tox.ini | 14 + 238 files changed, 2560 insertions(+), 5940 deletions(-) delete mode 100644 .dockerignore delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 LICENSE create mode 100644 MANIFEST.in delete mode 100644 Makefile delete mode 100644 SECURITY.md delete mode 100644 cookiecutter-config-file.yml create mode 100644 dev_requirements.txt delete mode 100644 poetry.lock delete mode 100644 pyproject.toml create mode 100644 pytest.ini rename {src => pythoncms}/.test.prod.env (100%) create mode 100644 pythoncms/CHANGELOG.md rename {src => pythoncms}/__init__.py (100%) create mode 100644 pythoncms/app.py rename src/autoapp.py => pythoncms/autoapp.py.example (95%) rename {src => pythoncms}/cli.py (74%) rename {src => pythoncms}/config.py (90%) rename {src => pythoncms}/config_demo.json (100%) rename {src => pythoncms}/conftest.py (76%) rename {src => pythoncms}/init.py (63%) rename {src => pythoncms}/manage.py (100%) create mode 100644 pythoncms/migrations/README create mode 100644 pythoncms/migrations/alembic.ini create mode 100644 pythoncms/migrations/env.py create mode 100644 pythoncms/migrations/script.py.mako create mode 100644 pythoncms/migrations/versions/cb42bf1aaf17_.py rename {src => pythoncms}/modules/__init__.py (100%) rename {src/modules/box__bizhelp/appointment => pythoncms/modules/box__default/appadmin}/__init__.py (100%) rename {src => pythoncms}/modules/box__default/appadmin/admin.py (75%) rename {src => pythoncms}/modules/box__default/appadmin/info.json (89%) rename {src => pythoncms}/modules/box__default/appadmin/models.py (100%) rename {src => pythoncms}/modules/box__default/appadmin/templates/appadmin/add.html (100%) rename {src => pythoncms}/modules/box__default/appadmin/templates/appadmin/blocks/sidebar.html (100%) rename {src => pythoncms}/modules/box__default/appadmin/templates/appadmin/edit.html (100%) rename {src => pythoncms}/modules/box__default/appadmin/templates/appadmin/index.html (100%) rename {src => pythoncms}/modules/box__default/appadmin/templates/appadmin/roles.html (100%) create mode 100644 pythoncms/modules/box__default/appadmin/tests/test_admin.py rename {src => pythoncms}/modules/box__default/appadmin/tests/test_models.py (100%) rename {src => pythoncms}/modules/box__default/appadmin/view.py (87%) rename {src => pythoncms}/modules/box__default/auth/decorators.py (100%) rename {src => pythoncms}/modules/box__default/auth/forms.py (100%) rename {src => pythoncms}/modules/box__default/auth/info.json (80%) rename {src => pythoncms}/modules/box__default/auth/models.py (99%) rename {src => pythoncms}/modules/box__default/auth/static/style.css (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/blocks/login_form.html (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/blocks/register_form.html (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/emails/activate_user.html (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/emails/activate_user.txt (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/login.html (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/register.html (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/shop_login.html (100%) rename {src => pythoncms}/modules/box__default/auth/templates/auth/unconfirmed.html (100%) rename {src => pythoncms}/modules/box__default/auth/tests/conftest.py (100%) rename {src => pythoncms}/modules/box__default/auth/tests/factories.py (99%) rename {src => pythoncms}/modules/box__default/auth/tests/test_auth_forms.py (100%) create mode 100644 pythoncms/modules/box__default/auth/tests/test_auth_functional.py rename {src => pythoncms}/modules/box__default/auth/tests/test_auth_models.py (54%) rename {src => pythoncms}/modules/box__default/auth/upload.py (100%) rename {src => pythoncms}/modules/box__default/auth/view.py (87%) create mode 100644 pythoncms/modules/box__default/base/info.json rename {src => pythoncms}/modules/box__default/base/templates/base/blocks/default_styles.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/blocks/flashed_messages.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/blocks/footer.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/blocks/macros.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/blocks/resources.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/main_base.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/module_base.html (100%) rename {src => pythoncms}/modules/box__default/base/templates/base/nav_base.html (100%) create mode 100644 pythoncms/modules/box__default/base/view.py rename {src => pythoncms}/modules/box__default/box_info.json (100%) create mode 100644 pythoncms/modules/box__default/dashboard/info.json rename {src => pythoncms}/modules/box__default/dashboard/templates/dashboard/index.html (100%) rename {src => pythoncms}/modules/box__default/dashboard/templates/dashboard/nav.html (100%) create mode 100644 pythoncms/modules/box__default/dashboard/tests/test_dashboard.py rename {src => pythoncms}/modules/box__default/dashboard/view.py (88%) rename {src/modules/box__default/theme => pythoncms/modules/box__default/i18n}/forms.py (100%) create mode 100644 pythoncms/modules/box__default/i18n/global.py create mode 100644 pythoncms/modules/box__default/i18n/helpers.py create mode 100644 pythoncms/modules/box__default/i18n/info.json create mode 100644 pythoncms/modules/box__default/i18n/models.py rename {src/modules/resource/templates/resource => pythoncms/modules/box__default/i18n/templates/i18n}/blocks/sidebar.html (100%) create mode 100644 pythoncms/modules/box__default/i18n/templates/i18n/dashboard.html create mode 100644 pythoncms/modules/box__default/i18n/tests/test_i18n_functional.py create mode 100644 pythoncms/modules/box__default/i18n/tests/test_i18n_models.py create mode 100644 pythoncms/modules/box__default/i18n/view.py rename {src/modules/box__bizhelp => pythoncms/modules/box__default}/page/forms.py (82%) rename {src/modules/box__bizhelp => pythoncms/modules/box__default}/page/info.json (100%) create mode 100644 pythoncms/modules/box__default/page/models.py rename {src/modules/box__bizhelp => pythoncms/modules/box__default}/page/templates/page/all_pages.html (54%) rename {src/modules/box__bizhelp => pythoncms/modules/box__default}/page/templates/page/blocks/sidebar.html (72%) rename {src/modules/box__bizhelp => pythoncms/modules/box__default}/page/templates/page/dashboard.html (93%) rename src/modules/box__bizhelp/people/__init__.py => pythoncms/modules/box__default/page/templates/page/dashboard_edit.html (100%) create mode 100644 pythoncms/modules/box__default/page/templates/page/view_page.html create mode 100644 pythoncms/modules/box__default/page/templates/page/view_page_dashboard.html create mode 100644 pythoncms/modules/box__default/page/view.py rename {src/modules/box__default/appadmin => pythoncms/modules/box__default/settings}/__init__.py (100%) rename {src => pythoncms}/modules/box__default/settings/helpers.py (100%) rename {src => pythoncms}/modules/box__default/settings/info.json (58%) rename {src => pythoncms}/modules/box__default/settings/models.py (100%) rename {src => pythoncms}/modules/box__default/settings/templates/settings/edit.html (100%) rename {src => pythoncms}/modules/box__default/settings/templates/settings/index.html (100%) rename {src => pythoncms}/modules/box__default/settings/templates/settings/nav.html (100%) rename {src => pythoncms}/modules/box__default/settings/upload.py (100%) rename {src => pythoncms}/modules/box__default/settings/view.py (100%) rename {src/modules/resource => pythoncms/modules/box__default/theme}/forms.py (100%) create mode 100644 pythoncms/modules/box__default/theme/global.py rename src/modules/box__default/theme/global.py => pythoncms/modules/box__default/theme/helper.py (78%) rename {src => pythoncms}/modules/box__default/theme/info.json (100%) rename {src => pythoncms}/modules/box__default/theme/models.py (100%) rename {src => pythoncms}/modules/box__default/theme/templates/theme/blocks/sidebar.html (100%) rename {src => pythoncms}/modules/box__default/theme/templates/theme/index.html (100%) rename {src => pythoncms}/modules/box__default/theme/view.py (99%) rename {src/modules/www => pythoncms/modules/resource}/forms.py (100%) create mode 100644 pythoncms/modules/resource/info.json rename {src => pythoncms}/modules/resource/models.py (100%) rename {src/modules/www/templates/www => pythoncms/modules/resource/templates/resource}/blocks/sidebar.html (100%) rename {src => pythoncms}/modules/resource/view.py (100%) rename src/modules/box__default/settings/__init__.py => pythoncms/modules/www/forms.py (100%) create mode 100644 pythoncms/modules/www/global.py rename {src => pythoncms}/modules/www/info.json (100%) rename {src => pythoncms}/modules/www/models.py (100%) rename src/static/themes/front/blogus/sections/footer.html => pythoncms/modules/www/templates/www/blocks/sidebar.html (100%) create mode 100644 pythoncms/modules/www/templates/www/index.html rename {src => pythoncms}/modules/www/view.py (60%) rename {src => pythoncms}/shopyo_admin.py (100%) rename {src => pythoncms}/static/bootstrap-grid.min.css (100%) rename {src => pythoncms}/static/bootstrap-reboot.min.css (100%) rename {src => pythoncms}/static/bootstrap.bundle.min.js (100%) rename {src => pythoncms}/static/bootstrap.min.css (100%) rename {src => pythoncms}/static/box.svg (100%) rename {src => pythoncms}/static/css/b4vtabs.min.css (100%) rename {src => pythoncms}/static/css/simple_sidebar.css (100%) rename {src => pythoncms}/static/default/default_product.jpg (100%) rename {src => pythoncms}/static/default/default_subcategory.jpg (100%) rename {src => pythoncms}/static/favicon.ico (100%) rename {src => pythoncms}/static/fontawesome/LICENSE.txt (100%) rename {src => pythoncms}/static/fontawesome/css/all.css (100%) rename {src => pythoncms}/static/fontawesome/css/all.min.css (100%) rename {src => pythoncms}/static/fontawesome/css/brands.css (100%) rename {src => pythoncms}/static/fontawesome/css/brands.min.css (100%) rename {src => pythoncms}/static/fontawesome/css/fontawesome.css (100%) rename {src => pythoncms}/static/fontawesome/css/fontawesome.min.css (100%) rename {src => pythoncms}/static/fontawesome/css/regular.css (100%) rename {src => pythoncms}/static/fontawesome/css/regular.min.css (100%) rename {src => pythoncms}/static/fontawesome/css/solid.css (100%) rename {src => pythoncms}/static/fontawesome/css/solid.min.css (100%) rename {src => pythoncms}/static/fontawesome/css/svg-with-js.css (100%) rename {src => pythoncms}/static/fontawesome/css/svg-with-js.min.css (100%) rename {src => pythoncms}/static/fontawesome/css/v4-shims.css (100%) rename {src => pythoncms}/static/fontawesome/css/v4-shims.min.css (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-brands-400.eot (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-brands-400.svg (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-brands-400.ttf (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-brands-400.woff (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-brands-400.woff2 (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-regular-400.eot (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-regular-400.svg (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-regular-400.ttf (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-regular-400.woff (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-regular-400.woff2 (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-solid-900.eot (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-solid-900.svg (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-solid-900.ttf (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-solid-900.woff (100%) rename {src => pythoncms}/static/fontawesome/webfonts/fa-solid-900.woff2 (100%) rename {src => pythoncms}/static/jquery_3.2.1.min.js (100%) rename {src => pythoncms}/static/js/python.js (100%) create mode 100644 pythoncms/static/modules/box__default/auth/style.css rename {src => pythoncms}/static/shopyo.png (100%) rename {src => pythoncms}/static/shopyo.svg (100%) rename {src => pythoncms}/static/themes/back/boogle/info.json (100%) rename {src => pythoncms}/static/themes/back/boogle/styles.css (100%) rename {src => pythoncms}/static/themes/back/mistrello/info.json (100%) rename {src => pythoncms}/static/themes/back/mistrello/styles.css (100%) rename {src => pythoncms}/static/themes/front/blogus/index.html (100%) rename {src => pythoncms}/static/themes/front/blogus/info.json (100%) rename {src => pythoncms}/static/themes/front/blogus/render_demo.html (100%) rename src/static/themes/front/blogus/sections/nav.html => pythoncms/static/themes/front/blogus/sections/footer.html (100%) rename src/static/themes/front/blogus/sections/resources.html => pythoncms/static/themes/front/blogus/sections/nav.html (100%) create mode 100644 pythoncms/static/themes/front/blogus/sections/resources.html rename {src => pythoncms}/static/themes/front/blogus/styles.css (100%) rename {src => pythoncms}/tests/conftest.py (99%) create mode 100644 pythoncms/tests/test_configs.py create mode 100644 pythoncms/tests/test_dunder_main.py create mode 100644 pythoncms/tests/test_manage.py rename src/wsgi.py => pythoncms/wsgi.py.example (99%) delete mode 100644 setup.cfg create mode 100644 setup.py delete mode 100644 src/app.py delete mode 100644 src/modules/box__bizhelp/appointment/info.json delete mode 100644 src/modules/box__bizhelp/appointment/models.py delete mode 100644 src/modules/box__bizhelp/appointment/templates/appointment/add.html delete mode 100644 src/modules/box__bizhelp/appointment/templates/appointment/blocks/sidebar.html delete mode 100644 src/modules/box__bizhelp/appointment/templates/appointment/edit.html delete mode 100644 src/modules/box__bizhelp/appointment/templates/appointment/index.html delete mode 100644 src/modules/box__bizhelp/appointment/templates/appointment/lookup.html delete mode 100644 src/modules/box__bizhelp/appointment/view.py delete mode 100644 src/modules/box__bizhelp/box_info.json delete mode 100644 src/modules/box__bizhelp/contact/forms.py delete mode 100644 src/modules/box__bizhelp/contact/global.py delete mode 100644 src/modules/box__bizhelp/contact/info.json delete mode 100644 src/modules/box__bizhelp/contact/models.py delete mode 100644 src/modules/box__bizhelp/contact/templates/contact/blocks/sidebar.html delete mode 100644 src/modules/box__bizhelp/contact/templates/contact/contact_form.html delete mode 100644 src/modules/box__bizhelp/contact/templates/contact/dashboard.html delete mode 100644 src/modules/box__bizhelp/contact/tests/test_contact.py delete mode 100644 src/modules/box__bizhelp/contact/view.py delete mode 100644 src/modules/box__bizhelp/page/models.py delete mode 100644 src/modules/box__bizhelp/page/templates/page/view_page.html delete mode 100644 src/modules/box__bizhelp/page/view.py delete mode 100644 src/modules/box__bizhelp/people/info.json delete mode 100644 src/modules/box__bizhelp/people/models.py delete mode 100644 src/modules/box__bizhelp/people/templates/people/add.html delete mode 100644 src/modules/box__bizhelp/people/templates/people/blocks/sidebar.html delete mode 100644 src/modules/box__bizhelp/people/templates/people/edit.html delete mode 100644 src/modules/box__bizhelp/people/templates/people/index.html delete mode 100644 src/modules/box__bizhelp/people/templates/people/lookup.html delete mode 100644 src/modules/box__bizhelp/people/view.py delete mode 100644 src/modules/box__default/appadmin/tests/test_admin.py delete mode 100644 src/modules/box__default/auth/email.py delete mode 100644 src/modules/box__default/auth/tests/test_auth_functional.py delete mode 100644 src/modules/box__default/auth/tests/test_email.py delete mode 100644 src/modules/box__default/base/info.json delete mode 100644 src/modules/box__default/base/view.py delete mode 100644 src/modules/box__default/dashboard/tests/test_dashboard.py delete mode 100644 src/modules/resource/info.json delete mode 100644 src/modules/www/templates/www/index.html delete mode 100644 src/tests/test_configs.py delete mode 100644 tests/test_example/test_hello.py create mode 100644 tox.ini diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 6be1e24..0000000 --- a/.dockerignore +++ /dev/null @@ -1,38 +0,0 @@ -# Git -.git -.gitignore -.github - -# Docker -.dockerignore - -# IDE -.idea -.vscode - -# Byte-compiled / optimized / DLL files -__pycache__/ -**/__pycache__/ -*.pyc -*.pyo -*.pyd -.Python -*.py[cod] -*$py.class -.pytest_cache/ -..mypy_cache/ - -# poetry -.venv - -# C extensions -*.so - -# Virtual environment -.venv -venv - -.DS_Store -.AppleDouble -.LSOverride -._* diff --git a/.gitignore b/.gitignore index de2d5e0..7b7cf29 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ parts/ sdist/ var/ wheels/ -share/python-wheels/ *.egg-info/ .installed.cfg *.egg @@ -39,17 +38,14 @@ pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ -.nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover -*.py,cover .hypothesis/ .pytest_cache/ -cover/ # Translations *.mo @@ -59,7 +55,6 @@ cover/ *.log local_settings.py db.sqlite3 -db.sqlite3-journal # Flask stuff: instance/ @@ -69,44 +64,19 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +_build/ # PyBuilder -.pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints -# IPython -profile_default/ -ipython_config.py - # pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff +.python-version + +# celery beat schedule file celerybeat-schedule -celerybeat.pid # SageMath parsed files *.sage.py @@ -132,21 +102,27 @@ venv.bak/ # mypy .mypy_cache/ -.dmypy.json -dmypy.json -# Pyre type checker -.pyre/ +# shopyo +test.db +testing.db +shopyo.db + +# pycharm +.idea/ + +# win +*.exe +*.cs +*.bat +*.vbs -# pytype static type analyzer -.pytype/ +# vscode +.vscode +workspace.code-workspace -# Cython debug symbols -cython_debug/ +# modules in static since present in modules +shopyo/static/modules/ -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +# ignore secrets +config.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b07f971..f196707 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,36 +1,25 @@ -default_language_version: - python: python3.7 - -default_stages: [commit, push] - repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.5.0 - hooks: - - id: check-yaml - - id: end-of-file-fixer - exclude: LICENSE - - - repo: local + - repo: https://github.com/asottile/pyupgrade + rev: v3.3.1 hooks: - id: pyupgrade - name: pyupgrade - entry: poetry run pyupgrade --py37-plus - types: [python] - language: system - - - repo: local + args: ["--py36-plus"] + - repo: https://github.com/asottile/reorder_python_imports + rev: v3.9.0 hooks: - - id: isort - name: isort - entry: poetry run isort --settings-path pyproject.toml - types: [python] - language: system - - - repo: local + - id: reorder-python-imports + name: Reorder Python imports + - repo: https://github.com/psf/black + rev: 22.12.0 hooks: - id: black - name: black - entry: poetry run black --config pyproject.toml - types: [python] - language: system + args: [--experimental-string-processing] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: fix-byte-order-marker + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: debug-statements + - id: check-added-large-files diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 62a818d..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at arj.python@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 16e880e..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,47 +0,0 @@ -# How to contribute - -## Dependencies - -We use `poetry` to manage the [dependencies](https://github.com/python-poetry/poetry). -If you dont have `poetry`, you should install with `make poetry-download`. - -To install dependencies and prepare [`pre-commit`](https://pre-commit.com/) hooks you would need to run `install` command: - -```bash -make install -make pre-commit-install -``` - -To activate your `virtualenv` run `poetry shell`. - -## Codestyle - -After installation you may execute code formatting. - -```bash -make codestyle -``` - -### Checks - -Many checks are configured for this project. Command `make check-codestyle` will check black, isort and darglint. -The `make check-safety` command will look at the security of your code. - -Comand `make lint` applies all checks. - -### Before submitting - -Before submitting your code please do the following steps: - -1. Add any changes you want -1. Add tests for the new changes -1. Edit documentation if you have changed something significant -1. Run `make codestyle` to format your changes. -1. Run `make lint` to ensure that types, security and docstrings are okay. - -## Other help - -You can contribute by spreading a word about this library. -It would also be a huge contribution to write -a short article on how you are using this project. -You can also share your best practices with us. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cbff657..0000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2022 shopyo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..3b44dad --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,8 @@ +include requirements.txt +include dev_requirements.txt +exclude config.json +recursive-include {projname} * +recursive-exclude {projname}/instance * +recursive-exclude {projname}/static/modules * +recursive-exclude {projname}/.tox * +recursive-exclude __pycache__ * diff --git a/Makefile b/Makefile deleted file mode 100644 index e3c2058..0000000 --- a/Makefile +++ /dev/null @@ -1,113 +0,0 @@ -#* Variables -SHELL := /usr/bin/env bash -PYTHON := python -PYTHONPATH := `pwd` - -#* Docker variables -IMAGE := pythoncms -VERSION := latest - -#* Poetry -.PHONY: poetry-download -poetry-download: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | $(PYTHON) - - -.PHONY: poetry-remove -poetry-remove: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | $(PYTHON) - --uninstall - -#* Installation -.PHONY: install -install: - poetry lock -n && poetry export --without-hashes > requirements.txt - poetry install -n - -poetry run mypy --install-types --non-interactive ./ - -.PHONY: pre-commit-install -pre-commit-install: - poetry run pre-commit install - -#* Formatters -.PHONY: codestyle -codestyle: - poetry run pyupgrade --exit-zero-even-if-changed --py37-plus **/*.py - poetry run isort --settings-path pyproject.toml ./ - poetry run black --config pyproject.toml ./ - -.PHONY: formatting -formatting: codestyle - -#* Linting -.PHONY: test -test: - PYTHONPATH=$(PYTHONPATH) poetry run pytest -c pyproject.toml --cov-report=html --cov=pythoncms tests/ - poetry run coverage-badge -o assets/images/coverage.svg -f - -.PHONY: check-codestyle -check-codestyle: - poetry run isort --diff --check-only --settings-path pyproject.toml ./ - poetry run black --diff --check --config pyproject.toml ./ - poetry run darglint --verbosity 2 pythoncms tests - -.PHONY: mypy -mypy: - poetry run mypy --config-file pyproject.toml ./ - -.PHONY: check-safety -check-safety: - poetry check - poetry run safety check --full-report - poetry run bandit -ll --recursive pythoncms tests - -.PHONY: lint -lint: test check-codestyle mypy check-safety - -.PHONY: update-dev-deps -update-dev-deps: - poetry add -D bandit@latest darglint@latest "isort[colors]@latest" mypy@latest pre-commit@latest pydocstyle@latest pylint@latest pytest@latest pyupgrade@latest safety@latest coverage@latest coverage-badge@latest pytest-html@latest pytest-cov@latest - poetry add -D --allow-prereleases black@latest - -#* Docker -# Example: make docker-build VERSION=latest -# Example: make docker-build IMAGE=some_name VERSION=0.1.0 -.PHONY: docker-build -docker-build: - @echo Building docker $(IMAGE):$(VERSION) ... - docker build \ - -t $(IMAGE):$(VERSION) . \ - -f ./docker/Dockerfile --no-cache - -# Example: make docker-remove VERSION=latest -# Example: make docker-remove IMAGE=some_name VERSION=0.1.0 -.PHONY: docker-remove -docker-remove: - @echo Removing docker $(IMAGE):$(VERSION) ... - docker rmi -f $(IMAGE):$(VERSION) - -#* Cleaning -.PHONY: pycache-remove -pycache-remove: - find . | grep -E "(__pycache__|\.pyc|\.pyo$$)" | xargs rm -rf - -.PHONY: dsstore-remove -dsstore-remove: - find . | grep -E ".DS_Store" | xargs rm -rf - -.PHONY: mypycache-remove -mypycache-remove: - find . | grep -E ".mypy_cache" | xargs rm -rf - -.PHONY: ipynbcheckpoints-remove -ipynbcheckpoints-remove: - find . | grep -E ".ipynb_checkpoints" | xargs rm -rf - -.PHONY: pytestcache-remove -pytestcache-remove: - find . | grep -E ".pytest_cache" | xargs rm -rf - -.PHONY: build-remove -build-remove: - rm -rf build/ - -.PHONY: cleanup -cleanup: pycache-remove dsstore-remove mypycache-remove ipynbcheckpoints-remove pytestcache-remove diff --git a/README.md b/README.md index 3efac75..d9fbe4f 100644 --- a/README.md +++ b/README.md @@ -1,404 +1 @@ -# pythoncms - -
- -[![Build status](https://github.com/shopyo/pythoncms/workflows/build/badge.svg?branch=master&event=push)](https://github.com/shopyo/pythoncms/actions?query=workflow%3Abuild) -[![Python Version](https://img.shields.io/pypi/pyversions/pythoncms.svg)](https://pypi.org/project/pythoncms/) -[![Dependencies Status](https://img.shields.io/badge/dependencies-up%20to%20date-brightgreen.svg)](https://github.com/shopyo/pythoncms/pulls?utf8=%E2%9C%93&q=is%3Apr%20author%3Aapp%2Fdependabot) - -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[![Security: bandit](https://img.shields.io/badge/security-bandit-green.svg)](https://github.com/PyCQA/bandit) -[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/shopyo/pythoncms/blob/master/.pre-commit-config.yaml) -[![Semantic Versions](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--versions-e10079.svg)](https://github.com/shopyo/pythoncms/releases) -[![License](https://img.shields.io/github/license/shopyo/pythoncms)](https://github.com/shopyo/pythoncms/blob/master/LICENSE) -![Coverage Report](assets/images/coverage.svg) - -Python CMS is an easy-to-use, instant-operations CMS - -
- -## Very first steps - -### Initialize your code - -1. Initialize `git` inside your repo: - -```bash -cd pythoncms && git init -``` - -2. If you don't have `Poetry` installed run: - -```bash -make poetry-download -``` - -3. Initialize poetry and install `pre-commit` hooks: - -```bash -make install -make pre-commit-install -``` - -4. Run the codestyle: - -```bash -make codestyle -``` - -5. Upload initial code to GitHub: - -```bash -git add . -git commit -m ":tada: Initial commit" -git branch -M main -git remote add origin https://github.com/shopyo/pythoncms.git -git push -u origin main -``` - -### Set up bots - -- Set up [Dependabot](https://docs.github.com/en/github/administering-a-repository/enabling-and-disabling-version-updates#enabling-github-dependabot-version-updates) to ensure you have the latest dependencies. -- Set up [Stale bot](https://github.com/apps/stale) for automatic issue closing. - -### Poetry - -Want to know more about Poetry? Check [its documentation](https://python-poetry.org/docs/). - -
-Details about Poetry -

- -Poetry's [commands](https://python-poetry.org/docs/cli/#commands) are very intuitive and easy to learn, like: - -- `poetry add numpy@latest` -- `poetry run pytest` -- `poetry publish --build` - -etc -

-
- -### Building and releasing your package - -Building a new version of the application contains steps: - -- Bump the version of your package `poetry version `. You can pass the new version explicitly, or a rule such as `major`, `minor`, or `patch`. For more details, refer to the [Semantic Versions](https://semver.org/) standard. -- Make a commit to `GitHub`. -- Create a `GitHub release`. -- And... publish πŸ™‚ `poetry publish --build` - -## 🎯 What's next - -Well, that's up to you πŸ’ͺ🏻. I can only recommend the packages and articles that helped me. - -- [`Typer`](https://github.com/tiangolo/typer) is great for creating CLI applications. -- [`Rich`](https://github.com/willmcgugan/rich) makes it easy to add beautiful formatting in the terminal. -- [`Pydantic`](https://github.com/samuelcolvin/pydantic/) – data validation and settings management using Python type hinting. -- [`Loguru`](https://github.com/Delgan/loguru) makes logging (stupidly) simple. -- [`tqdm`](https://github.com/tqdm/tqdm) – fast, extensible progress bar for Python and CLI. -- [`IceCream`](https://github.com/gruns/icecream) is a little library for sweet and creamy debugging. -- [`orjson`](https://github.com/ijl/orjson) – ultra fast JSON parsing library. -- [`Returns`](https://github.com/dry-python/returns) makes you function's output meaningful, typed, and safe! -- [`Hydra`](https://github.com/facebookresearch/hydra) is a framework for elegantly configuring complex applications. -- [`FastAPI`](https://github.com/tiangolo/fastapi) is a type-driven asynchronous web framework. - -Articles: - -- [Open Source Guides](https://opensource.guide/). -- [A handy guide to financial support for open source](https://github.com/nayafia/lemonade-stand) -- [GitHub Actions Documentation](https://help.github.com/en/actions). -- Maybe you would like to add [gitmoji](https://gitmoji.carloscuesta.me/) to commit names. This is really funny. πŸ˜„ - -## πŸš€ Features - -### Development features - -- Supports for `Python 3.7` and higher. -- [`Poetry`](https://python-poetry.org/) as the dependencies manager. See configuration in [`pyproject.toml`](https://github.com/shopyo/pythoncms/blob/master/pyproject.toml) and [`setup.cfg`](https://github.com/shopyo/pythoncms/blob/master/setup.cfg). -- Automatic codestyle with [`black`](https://github.com/psf/black), [`isort`](https://github.com/timothycrosley/isort) and [`pyupgrade`](https://github.com/asottile/pyupgrade). -- Ready-to-use [`pre-commit`](https://pre-commit.com/) hooks with code-formatting. -- Type checks with [`mypy`](https://mypy.readthedocs.io); docstring checks with [`darglint`](https://github.com/terrencepreilly/darglint); security checks with [`safety`](https://github.com/pyupio/safety) and [`bandit`](https://github.com/PyCQA/bandit) -- Testing with [`pytest`](https://docs.pytest.org/en/latest/). -- Ready-to-use [`.editorconfig`](https://github.com/shopyo/pythoncms/blob/master/.editorconfig), [`.dockerignore`](https://github.com/shopyo/pythoncms/blob/master/.dockerignore), and [`.gitignore`](https://github.com/shopyo/pythoncms/blob/master/.gitignore). You don't have to worry about those things. - -### Deployment features - -- `GitHub` integration: issue and pr templates. -- `Github Actions` with predefined [build workflow](https://github.com/shopyo/pythoncms/blob/master/.github/workflows/build.yml) as the default CI/CD. -- Everything is already set up for security checks, codestyle checks, code formatting, testing, linting, docker builds, etc with [`Makefile`](https://github.com/shopyo/pythoncms/blob/master/Makefile#L89). More details in [makefile-usage](#makefile-usage). -- [Dockerfile](https://github.com/shopyo/pythoncms/blob/master/docker/Dockerfile) for your package. -- Always up-to-date dependencies with [`@dependabot`](https://dependabot.com/). You will only [enable it](https://docs.github.com/en/github/administering-a-repository/enabling-and-disabling-version-updates#enabling-github-dependabot-version-updates). -- Automatic drafts of new releases with [`Release Drafter`](https://github.com/marketplace/actions/release-drafter). You may see the list of labels in [`release-drafter.yml`](https://github.com/shopyo/pythoncms/blob/master/.github/release-drafter.yml). Works perfectly with [Semantic Versions](https://semver.org/) specification. - -### Open source community features - -- Ready-to-use [Pull Requests templates](https://github.com/shopyo/pythoncms/blob/master/.github/PULL_REQUEST_TEMPLATE.md) and several [Issue templates](https://github.com/shopyo/pythoncms/tree/master/.github/ISSUE_TEMPLATE). -- Files such as: `LICENSE`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `SECURITY.md` are generated automatically. -- [`Stale bot`](https://github.com/apps/stale) that closes abandoned issues after a period of inactivity. (You will only [need to setup free plan](https://github.com/marketplace/stale)). Configuration is [here](https://github.com/shopyo/pythoncms/blob/master/.github/.stale.yml). -- [Semantic Versions](https://semver.org/) specification with [`Release Drafter`](https://github.com/marketplace/actions/release-drafter). - -## Installation - -```bash -pip install -U pythoncms -``` - -or install with `Poetry` - -```bash -poetry add pythoncms -``` - -Then you can run - -```bash -pythoncms --help -``` - -or with `Poetry`: - -```bash -poetry run pythoncms --help -``` - -### Makefile usage - -[`Makefile`](https://github.com/shopyo/pythoncms/blob/master/Makefile) contains a lot of functions for faster development. - -
-1. Download and remove Poetry -

- -To download and install Poetry run: - -```bash -make poetry-download -``` - -To uninstall - -```bash -make poetry-remove -``` - -

-
- -
-2. Install all dependencies and pre-commit hooks -

- -Install requirements: - -```bash -make install -``` - -Pre-commit hooks coulb be installed after `git init` via - -```bash -make pre-commit-install -``` - -

-
- -
-3. Codestyle -

- -Automatic formatting uses `pyupgrade`, `isort` and `black`. - -```bash -make codestyle - -# or use synonym -make formatting -``` - -Codestyle checks only, without rewriting files: - -```bash -make check-codestyle -``` - -> Note: `check-codestyle` uses `isort`, `black` and `darglint` library - -Update all dev libraries to the latest version using one comand - -```bash -make update-dev-deps -``` - -

-4. Code security -

- -```bash -make check-safety -``` - -This command launches `Poetry` integrity checks as well as identifies security issues with `Safety` and `Bandit`. - -```bash -make check-safety -``` - -

-
- -

-
- -
-5. Type checks -

- -Run `mypy` static type checker - -```bash -make mypy -``` - -

-
- -
-6. Tests with coverage badges -

- -Run `pytest` - -```bash -make test -``` - -

-
- -
-7. All linters -

- -Of course there is a command to ~~rule~~ run all linters in one: - -```bash -make lint -``` - -the same as: - -```bash -make test && make check-codestyle && make mypy && make check-safety -``` - -

-
- -
-8. Docker -

- -```bash -make docker-build -``` - -which is equivalent to: - -```bash -make docker-build VERSION=latest -``` - -Remove docker image with - -```bash -make docker-remove -``` - -More information [about docker](https://github.com/shopyo/pythoncms/tree/master/docker). - -

-
- -
-9. Cleanup -

-Delete pycache files - -```bash -make pycache-remove -``` - -Remove package build - -```bash -make build-remove -``` - -Delete .DS_STORE files - -```bash -make dsstore-remove -``` - -Remove .mypycache - -```bash -make mypycache-remove -``` - -Or to remove all above run: - -```bash -make cleanup -``` - -

-
- -## πŸ“ˆ Releases - -You can see the list of available releases on the [GitHub Releases](https://github.com/shopyo/pythoncms/releases) page. - -We follow [Semantic Versions](https://semver.org/) specification. - -We use [`Release Drafter`](https://github.com/marketplace/actions/release-drafter). As pull requests are merged, a draft release is kept up-to-date listing the changes, ready to publish when you’re ready. With the categories option, you can categorize pull requests in release notes using labels. - -### List of labels and corresponding titles - -| **Label** | **Title in Releases** | -| :-----------------------------------: | :---------------------: | -| `enhancement`, `feature` | πŸš€ Features | -| `bug`, `refactoring`, `bugfix`, `fix` | πŸ”§ Fixes & Refactoring | -| `build`, `ci`, `testing` | πŸ“¦ Build System & CI/CD | -| `breaking` | πŸ’₯ Breaking Changes | -| `documentation` | πŸ“ Documentation | -| `dependencies` | ⬆️ Dependencies updates | - -You can update it in [`release-drafter.yml`](https://github.com/shopyo/pythoncms/blob/master/.github/release-drafter.yml). - -GitHub creates the `bug`, `enhancement`, and `documentation` labels for you. Dependabot creates the `dependencies` label. Create the remaining labels on the Issues tab of your GitHub repository, when you need them. - -## πŸ›‘ License - -[![License](https://img.shields.io/github/license/shopyo/pythoncms)](https://github.com/shopyo/pythoncms/blob/master/LICENSE) - -This project is licensed under the terms of the `MIT` license. See [LICENSE](https://github.com/shopyo/pythoncms/blob/master/LICENSE) for more details. - -## πŸ“ƒ Citation - -```bibtex -@misc{pythoncms, - author = {shopyo}, - title = {Python CMS is an easy-to-use, instant-operations CMS}, - year = {2022}, - publisher = {GitHub}, - journal = {GitHub repository}, - howpublished = {\url{https://github.com/shopyo/pythoncms}} -} -``` - -## Credits [![πŸš€ Your next Python package needs a bleeding-edge project structure.](https://img.shields.io/badge/python--package--template-%F0%9F%9A%80-brightgreen)](https://github.com/TezRomacH/python-package-template) - -This project was generated with [`python-package-template`](https://github.com/TezRomacH/python-package-template) +# Welcome to pythoncms diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 85f5260..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,27 +0,0 @@ -# Security - -## πŸ” Reporting Security Issues - -> Do not open issues that might have security implications! -> It is critical that security related issues are reported privately so we have time to address them before they become public knowledge. - -Vulnerabilities can be reported by emailing core members: - -- shopyo [arj.python@gmail.com](mailto:arj.python@gmail.com) - -Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: - -- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) -- Full paths of source file(s) related to the manifestation of the issue -- The location of the affected source code (tag/branch/commit or direct URL) -- Any special configuration required to reproduce the issue -- Environment (e.g. Linux / Windows / macOS) -- Step-by-step instructions to reproduce the issue -- Proof-of-concept or exploit code (if possible) -- Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -## Preferred Languages - -We prefer all communications to be in English. diff --git a/cookiecutter-config-file.yml b/cookiecutter-config-file.yml deleted file mode 100644 index a90adfc..0000000 --- a/cookiecutter-config-file.yml +++ /dev/null @@ -1,13 +0,0 @@ -# This file contains values from Cookiecutter - -default_context: - project_name: "pythoncms" - project_description: "Python CMS is an easy-to-use, instant-operations CMS" - organization: "shopyo" - license: "MIT" - minimal_python_version: 3.7 - github_name: "shopyo" - email: "arj.python@gmail.com" - version: "0.1.0" - line_length: "88" - create_example_template: "cli" diff --git a/dev_requirements.txt b/dev_requirements.txt new file mode 100644 index 0000000..d2102cc --- /dev/null +++ b/dev_requirements.txt @@ -0,0 +1,12 @@ +flake8==3.8.4 +black==20.8b1 +isort==5.6.4 +Sphinx==3.2.1 +pytest==6.1.1 +pytest-order==0.9.5 +tox==3.21.0 +pytest-cov==2.11.1 +codecov==2.1.11 +factory-boy==3.2.0 +freezegun==1.1.0 +pytest-dotenv diff --git a/docs/conf.py b/docs/conf.py index ece59e9..b7e2937 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,7 +3,6 @@ # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html - # -- Path setup -------------------------------------------------------------- # # If extensions (or modules to document with autodoc) are in another directory, @@ -16,7 +15,7 @@ # # -- Project information ----------------------------------------------------- -project = "src" +project = "pythoncms" author = "" # -- General configuration --------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index a225940..45fd906 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -Welcome to src docs! +Welcome to pythoncms docs! ============================ Write project description here diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 07ba439..0000000 --- a/poetry.lock +++ /dev/null @@ -1,1767 +0,0 @@ -[[package]] -name = "alembic" -version = "1.7.7" -description = "A database migration tool for SQLAlchemy." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.9\""} -importlib-resources = {version = "*", markers = "python_version < \"3.9\""} -Mako = "*" -SQLAlchemy = ">=1.3.0" - -[package.extras] -tz = ["python-dateutil"] - -[[package]] -name = "astroid" -version = "2.9.3" -description = "An abstract syntax tree for Python with inference support." -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -lazy-object-proxy = ">=1.4.0" -typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} -wrapt = ">=1.11,<1.14" - -[[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "attrs" -version = "21.4.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] - -[[package]] -name = "bandit" -version = "1.7.4" -description = "Security oriented static analyser for python code." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} -GitPython = ">=1.0.1" -PyYAML = ">=5.3.1" -stevedore = ">=1.20.0" - -[package.extras] -test = ["coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml", "beautifulsoup4 (>=4.8.0)", "pylint (==1.9.4)"] -toml = ["toml"] -yaml = ["pyyaml"] - -[[package]] -name = "black" -version = "21.12b0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -click = ">=7.1.2" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0,<1" -platformdirs = ">=2" -tomli = ">=0.2.6,<2.0.0" -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = [ - {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, - {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, -] - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -python2 = ["typed-ast (>=1.4.3)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "certifi" -version = "2021.10.8" -description = "Python package for providing Mozilla's CA Bundle." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "cfgv" -version = "3.3.1" -description = "Validate configuration and produce human readable error messages." -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[[package]] -name = "charset-normalizer" -version = "2.0.12" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" -optional = false -python-versions = ">=3.5.0" - -[package.extras] -unicode_backport = ["unicodedata2"] - -[[package]] -name = "click" -version = "8.0.4" -description = "Composable command line interface toolkit" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - -[[package]] -name = "colorama" -version = "0.4.4" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "commonmark" -version = "0.9.1" -description = "Python parser for the CommonMark Markdown spec" -category = "main" -optional = false -python-versions = "*" - -[package.extras] -test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] - -[[package]] -name = "coverage" -version = "6.3.2" -description = "Code coverage measurement for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "coverage-badge" -version = "1.1.0" -description = "Generate coverage badges for Coverage.py." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -coverage = "*" - -[[package]] -name = "darglint" -version = "1.8.1" -description = "A utility for ensuring Google-style docstrings stay up to date with the source code." -category = "dev" -optional = false -python-versions = ">=3.6,<4.0" - -[[package]] -name = "distlib" -version = "0.3.4" -description = "Distribution utilities" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "dparse" -version = "0.5.1" -description = "A parser for Python dependency files" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -packaging = "*" -pyyaml = "*" -toml = "*" - -[package.extras] -pipenv = ["pipenv"] - -[[package]] -name = "filelock" -version = "3.6.0" -description = "A platform independent file lock." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] -testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] - -[[package]] -name = "flask" -version = "2.0.3" -description = "A simple framework for building complex web applications." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -click = ">=7.1.2" -itsdangerous = ">=2.0" -Jinja2 = ">=3.0" -Werkzeug = ">=2.0" - -[package.extras] -async = ["asgiref (>=3.2)"] -dotenv = ["python-dotenv"] - -[[package]] -name = "flask-admin" -version = "1.6.0" -description = "Simple and extensible admin interface framework for Flask" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -Flask = ">=0.7" -wtforms = "*" - -[package.extras] -aws = ["boto"] -azure = ["azure-storage-blob"] - -[[package]] -name = "flask-login" -version = "0.5.0" -description = "User session management for Flask" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -Flask = "*" - -[[package]] -name = "flask-mailman" -version = "0.3.0" -description = "Porting Django's email implementation to your Flask applications." -category = "main" -optional = false -python-versions = ">=3.6.2,<4.0.0" - -[package.dependencies] -flask = ">=1.0" -mkdocs-material-extensions = ">=1.0.1,<2.0.0" - -[package.extras] -test = ["black (>=21.5b2,<22.0)", "flake8 (>=3.9.2,<4.0.0)", "isort (>=5.8.0,<6.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<3.0.0)"] -dev = ["bump2version (>=1.0.1,<2.0.0)", "pip (>=20.3.1,<21.0.0)", "pre-commit (>=2.12.0,<3.0.0)", "toml (>=0.10.2,<0.11.0)", "tox (>=3.20.1,<4.0.0)", "twine (>=3.3.0,<4.0.0)", "virtualenv (>=20.2.2,<21.0.0)"] -doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-autorefs (>=0.2.1,<0.3.0)", "mkdocs-include-markdown-plugin (>=1.0.0,<2.0.0)", "mkdocs-material (>=6.1.7,<7.0.0)", "mkdocstrings (>=0.15.2,<0.16.0)"] - -[[package]] -name = "flask-marshmallow" -version = "0.14.0" -description = "Flask + marshmallow for beautiful APIs" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -Flask = "*" -marshmallow = ">=2.0.0" -six = ">=1.9.0" - -[package.extras] -dev = ["flask-sqlalchemy", "pytest", "mock", "flake8 (==3.8.3)", "pre-commit (>=2.4,<3.0)", "tox", "marshmallow-sqlalchemy (>=0.13.0,<0.19.0)", "flake8-bugbear (==20.1.4)", "marshmallow-sqlalchemy (>=0.13.0)"] -docs = ["marshmallow-sqlalchemy (>=0.13.0)", "Sphinx (==3.2.1)", "sphinx-issues (==1.2.0)"] -lint = ["flake8 (==3.8.3)", "pre-commit (>=2.4,<3.0)", "flake8-bugbear (==20.1.4)"] -sqlalchemy = ["flask-sqlalchemy", "marshmallow-sqlalchemy (>=0.13.0,<0.19.0)", "marshmallow-sqlalchemy (>=0.13.0)"] -tests = ["flask-sqlalchemy", "pytest", "mock", "marshmallow-sqlalchemy (>=0.13.0,<0.19.0)", "marshmallow-sqlalchemy (>=0.13.0)"] - -[[package]] -name = "flask-migrate" -version = "3.1.0" -description = "SQLAlchemy database migrations for Flask applications using Alembic." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -alembic = ">=0.7" -Flask = ">=0.9" -Flask-SQLAlchemy = ">=1.0" - -[[package]] -name = "flask-sqlalchemy" -version = "2.5.1" -description = "Adds SQLAlchemy support to your Flask application." -category = "main" -optional = false -python-versions = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*" - -[package.dependencies] -Flask = ">=0.10" -SQLAlchemy = ">=0.8.0" - -[[package]] -name = "flask-wtf" -version = "1.0.0" -description = "Form rendering, validation, and CSRF protection for Flask with WTForms." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -Flask = "*" -itsdangerous = "*" -WTForms = "*" - -[package.extras] -email = ["email-validator"] - -[[package]] -name = "gitdb" -version = "4.0.9" -description = "Git Object Database" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -smmap = ">=3.0.1,<6" - -[[package]] -name = "gitpython" -version = "3.1.27" -description = "GitPython is a python library used to interact with Git repositories" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} - -[[package]] -name = "greenlet" -version = "1.1.2" -description = "Lightweight in-process concurrent programming" -category = "main" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" - -[package.extras] -docs = ["sphinx"] - -[[package]] -name = "identify" -version = "2.4.12" -description = "File identification library for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "idna" -version = "3.3" -description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "importlib-metadata" -version = "4.11.3" -description = "Read metadata from Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] -perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] - -[[package]] -name = "importlib-resources" -version = "5.4.0" -description = "Read resources from Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "isort" -version = "5.10.1" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.6.1,<4.0" - -[package.dependencies] -colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"colors\""} - -[package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] -colors = ["colorama (>=0.4.3,<0.5.0)"] -plugins = ["setuptools"] - -[[package]] -name = "itsdangerous" -version = "2.1.1" -description = "Safely pass data to untrusted environments and back." -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "jinja2" -version = "3.0.3" -description = "A very fast and expressive template engine." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "lazy-object-proxy" -version = "1.7.1" -description = "A fast and thorough lazy object proxy." -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "mako" -version = "1.2.0" -description = "A super-fast templating language that borrows the best ideas from the existing templating languages." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -MarkupSafe = ">=0.9.2" - -[package.extras] -babel = ["babel"] -lingua = ["lingua"] -testing = ["pytest"] - -[[package]] -name = "markupsafe" -version = "2.1.1" -description = "Safely add untrusted strings to HTML/XML markup." -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "marshmallow" -version = "3.15.0" -description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -packaging = "*" - -[package.extras] -dev = ["pytest", "pytz", "simplejson", "mypy (==0.940)", "flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "pre-commit (>=2.4,<3.0)", "tox"] -docs = ["sphinx (==4.4.0)", "sphinx-issues (==3.0.1)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.7)"] -lint = ["mypy (==0.940)", "flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "pre-commit (>=2.4,<3.0)"] -tests = ["pytest", "pytz", "simplejson"] - -[[package]] -name = "marshmallow-sqlalchemy" -version = "0.28.0" -description = "SQLAlchemy integration with the marshmallow (de)serialization library" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -marshmallow = ">=3.0.0" -SQLAlchemy = ">=1.3.0" - -[package.extras] -dev = ["pytest", "pytest-lazy-fixture (>=0.6.2)", "flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "pre-commit (>=2.0,<3.0)", "tox"] -docs = ["sphinx (==4.4.0)", "alabaster (==0.7.12)", "sphinx-issues (==3.0.1)"] -lint = ["flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "pre-commit (>=2.0,<3.0)"] -tests = ["pytest", "pytest-lazy-fixture (>=0.6.2)"] - -[[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "mkdocs-material-extensions" -version = "1.0.3" -description = "Extension pack for Python Markdown." -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "mypy" -version = "0.910" -description = "Optional static typing for Python" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -mypy-extensions = ">=0.4.3,<0.5.0" -toml = "*" -typed-ast = {version = ">=1.4.0,<1.5.0", markers = "python_version < \"3.8\""} -typing-extensions = ">=3.7.4" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<1.5.0)"] - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "nodeenv" -version = "1.6.0" -description = "Node.js virtual environment builder" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "packaging" -version = "21.3" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - -[[package]] -name = "pathspec" -version = "0.9.0" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "pbr" -version = "5.8.1" -description = "Python Build Reasonableness" -category = "dev" -optional = false -python-versions = ">=2.6" - -[[package]] -name = "platformdirs" -version = "2.5.1" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pre-commit" -version = "2.17.0" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -toml = "*" -virtualenv = ">=20.0.8" - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pydocstyle" -version = "6.1.1" -description = "Python docstring style checker" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -snowballstemmer = "*" - -[package.extras] -toml = ["toml"] - -[[package]] -name = "pygments" -version = "2.11.2" -description = "Pygments is a syntax highlighting package written in Python." -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "pylint" -version = "2.12.2" -description = "python code static checker" -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -astroid = ">=2.9.0,<2.10" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.7" -platformdirs = ">=2.2.0" -toml = ">=0.9.2" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} - -[[package]] -name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pytest" -version = "6.2.5" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -toml = "*" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "3.0.0" -description = "Pytest plugin for measuring coverage." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] - -[[package]] -name = "pytest-html" -version = "3.1.1" -description = "pytest plugin for generating HTML reports" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pytest = ">=5.0,<6.0.0 || >6.0.0" -pytest-metadata = "*" - -[[package]] -name = "pytest-metadata" -version = "1.11.0" -description = "pytest plugin for test session metadata" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[package.dependencies] -pytest = ">=2.9.0" - -[[package]] -name = "pyupgrade" -version = "2.31.1" -description = "A tool to automatically upgrade syntax for newer versions." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tokenize-rt = ">=3.2.0" - -[[package]] -name = "pyyaml" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "requests" -version = "2.27.1" -description = "Python HTTP for Humans." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] - -[[package]] -name = "rich" -version = "10.16.2" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "main" -optional = false -python-versions = ">=3.6.2,<4.0.0" - -[package.dependencies] -colorama = ">=0.4.0,<0.5.0" -commonmark = ">=0.9.0,<0.10.0" -pygments = ">=2.6.0,<3.0.0" -typing-extensions = {version = ">=3.7.4,<5.0", markers = "python_version < \"3.8\""} - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] - -[[package]] -name = "safety" -version = "1.10.3" -description = "Checks installed dependencies for known vulnerabilities." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -Click = ">=6.0" -dparse = ">=0.5.1" -packaging = "*" -requests = "*" - -[[package]] -name = "shellingham" -version = "1.4.0" -description = "Tool to Detect Surrounding Shell" -category = "main" -optional = false -python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6" - -[[package]] -name = "shopyo" -version = "4.2.1" -description = "Highly modular web framework built on top of Flask with Django advantages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -Flask = ">=2.0.2" -Flask-Admin = ">=1.5.8" -Flask-Login = ">=0.5.0" -flask-mailman = ">=0.3.0" -flask-marshmallow = ">=0.14.0" -Flask-Migrate = ">=3.1.0" -Flask-SQLAlchemy = ">=2.5.1" -Flask-WTF = ">=1.0.0" -marshmallow = ">=3.14.0" -marshmallow-sqlalchemy = ">=0.26.1" -SQLAlchemy = ">=1.4.27" -Werkzeug = ">=2.0.2" -WTForms = ">=3.0.0" - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "smmap" -version = "5.0.0" -description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "sqlalchemy" -version = "1.4.32" -description = "Database Abstraction Library" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - -[package.extras] -aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] -aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3)"] -mariadb_connector = ["mariadb (>=1.0.1)"] -mssql = ["pyodbc"] -mssql_pymssql = ["pymssql"] -mssql_pyodbc = ["pyodbc"] -mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] -mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] -mysql_connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] -postgresql_pg8000 = ["pg8000 (>=1.16.6)"] -postgresql_psycopg2binary = ["psycopg2-binary"] -postgresql_psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql (<1)", "pymysql"] -sqlcipher = ["sqlcipher3-binary"] - -[[package]] -name = "stevedore" -version = "3.5.0" -description = "Manage dynamic plugins for Python applications" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} -pbr = ">=2.0.0,<2.1.0 || >2.1.0" - -[[package]] -name = "tokenize-rt" -version = "4.2.1" -description = "A wrapper around the stdlib `tokenize` which roundtrips." -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "tomli" -version = "1.2.3" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "typed-ast" -version = "1.4.3" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "typer" -version = "0.4.0" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -click = ">=7.1.1,<9.0.0" -colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} -shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} - -[package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"] -dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"] -doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown-include (>=0.5.1,<0.6.0)"] -test = ["shellingham (>=1.3.0,<2.0.0)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "coverage (>=5.2,<6.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "mypy (==0.910)", "black (>=19.10b0,<20.0b0)", "isort (>=5.0.6,<6.0.0)"] - -[[package]] -name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "urllib3" -version = "1.26.9" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" - -[package.extras] -brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "virtualenv" -version = "20.13.4" -description = "Virtual Python Environment builder" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[package.dependencies] -distlib = ">=0.3.1,<1" -filelock = ">=3.2,<4" -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} -platformdirs = ">=2,<3" -six = ">=1.9.0,<2" - -[package.extras] -docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] -testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] - -[[package]] -name = "werkzeug" -version = "2.0.3" -description = "The comprehensive WSGI web application library." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -watchdog = ["watchdog"] - -[[package]] -name = "wrapt" -version = "1.13.3" -description = "Module for decorators, wrappers and monkey patching." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "wtforms" -version = "3.0.1" -description = "Form validation and rendering for Python web development." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -MarkupSafe = "*" - -[package.extras] -email = ["email-validator"] - -[[package]] -name = "zipp" -version = "3.7.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.7" -content-hash = "6d56f8dc1d83ac319d2b72d59c4f8459fbb916b1ee19b714638e35c7d029d2f2" - -[metadata.files] -alembic = [ - {file = "alembic-1.7.7-py3-none-any.whl", hash = "sha256:29be0856ec7591c39f4e1cb10f198045d890e6e2274cf8da80cb5e721a09642b"}, - {file = "alembic-1.7.7.tar.gz", hash = "sha256:4961248173ead7ce8a21efb3de378f13b8398e6630fab0eb258dc74a8af24c58"}, -] -astroid = [ - {file = "astroid-2.9.3-py3-none-any.whl", hash = "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"}, - {file = "astroid-2.9.3.tar.gz", hash = "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877"}, -] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] -attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, -] -bandit = [ - {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, - {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"}, -] -black = [ - {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, - {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, -] -certifi = [ - {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, - {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, -] -cfgv = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, -] -click = [ - {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, - {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, -] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -commonmark = [ - {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, - {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, -] -coverage = [ - {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, - {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, - {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, - {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, - {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, - {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, - {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, - {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, - {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, - {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, - {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, - {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, - {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, - {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, - {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, - {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, - {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, -] -coverage-badge = [ - {file = "coverage-badge-1.1.0.tar.gz", hash = "sha256:c824a106503e981c02821e7d32f008fb3984b2338aa8c3800ec9357e33345b78"}, - {file = "coverage_badge-1.1.0-py2.py3-none-any.whl", hash = "sha256:e365d56e5202e923d1b237f82defd628a02d1d645a147f867ac85c58c81d7997"}, -] -darglint = [ - {file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"}, - {file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"}, -] -distlib = [ - {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, - {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, -] -dparse = [ - {file = "dparse-0.5.1-py3-none-any.whl", hash = "sha256:e953a25e44ebb60a5c6efc2add4420c177f1d8404509da88da9729202f306994"}, - {file = "dparse-0.5.1.tar.gz", hash = "sha256:a1b5f169102e1c894f9a7d5ccf6f9402a836a5d24be80a986c7ce9eaed78f367"}, -] -filelock = [ - {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"}, - {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, -] -flask = [ - {file = "Flask-2.0.3-py3-none-any.whl", hash = "sha256:59da8a3170004800a2837844bfa84d49b022550616070f7cb1a659682b2e7c9f"}, - {file = "Flask-2.0.3.tar.gz", hash = "sha256:e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d"}, -] -flask-admin = [ - {file = "Flask-Admin-1.6.0.tar.gz", hash = "sha256:424ffc79b7b0dfff051555686ea12e86e48dffacac14beaa319fb4502ac40988"}, -] -flask-login = [ - {file = "Flask-Login-0.5.0.tar.gz", hash = "sha256:6d33aef15b5bcead780acc339464aae8a6e28f13c90d8b1cf9de8b549d1c0b4b"}, - {file = "Flask_Login-0.5.0-py2.py3-none-any.whl", hash = "sha256:7451b5001e17837ba58945aead261ba425fdf7b4f0448777e597ddab39f4fba0"}, -] -flask-mailman = [ - {file = "Flask-Mailman-0.3.0.tar.gz", hash = "sha256:faa945585a985e475393f83b210b32b3577400233b0584dd9a32f1d13e152ba8"}, - {file = "Flask_Mailman-0.3.0-py3-none-any.whl", hash = "sha256:323700baff52ad3ab27c49f8bf38ca63d4f436dce89ff307a3ef0a65e084b25d"}, -] -flask-marshmallow = [ - {file = "flask-marshmallow-0.14.0.tar.gz", hash = "sha256:bd01a6372cbe50e36f205cfff0fc5dab0b7b662c4c8b2c4fc06a3151b2950950"}, - {file = "flask_marshmallow-0.14.0-py2.py3-none-any.whl", hash = "sha256:2adcd782b5a4a6c5ae3c96701f320d8ca6997995a52b2661093c56cc3ed24754"}, -] -flask-migrate = [ - {file = "Flask-Migrate-3.1.0.tar.gz", hash = "sha256:57d6060839e3a7f150eaab6fe4e726d9e3e7cffe2150fb223d73f92421c6d1d9"}, - {file = "Flask_Migrate-3.1.0-py3-none-any.whl", hash = "sha256:a6498706241aba6be7a251078de9cf166d74307bca41a4ca3e403c9d39e2f897"}, -] -flask-sqlalchemy = [ - {file = "Flask-SQLAlchemy-2.5.1.tar.gz", hash = "sha256:2bda44b43e7cacb15d4e05ff3cc1f8bc97936cc464623424102bfc2c35e95912"}, - {file = "Flask_SQLAlchemy-2.5.1-py2.py3-none-any.whl", hash = "sha256:f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390"}, -] -flask-wtf = [ - {file = "Flask-WTF-1.0.0.tar.gz", hash = "sha256:872fbb17b5888bfc734edbdcf45bc08fb365ca39f69d25dc752465a455517b28"}, - {file = "Flask_WTF-1.0.0-py3-none-any.whl", hash = "sha256:01feccfc395405cea48a3f36c23f0d766e2cc6fd2a5a065ad50ad3e5827ec797"}, -] -gitdb = [ - {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, - {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, -] -gitpython = [ - {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, - {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, -] -greenlet = [ - {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, - {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, - {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"}, - {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"}, - {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"}, - {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"}, - {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"}, - {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, - {file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"}, - {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, - {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, - {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, - {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"}, - {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"}, - {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"}, - {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, - {file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"}, - {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, - {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, - {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, - {file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"}, - {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, - {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, - {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, - {file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"}, - {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, - {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, - {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, - {file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"}, - {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, - {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, - {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, -] -identify = [ - {file = "identify-2.4.12-py2.py3-none-any.whl", hash = "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323"}, - {file = "identify-2.4.12.tar.gz", hash = "sha256:3f3244a559290e7d3deb9e9adc7b33594c1bc85a9dd82e0f1be519bf12a1ec17"}, -] -idna = [ - {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, - {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, -] -importlib-metadata = [ - {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, - {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, -] -importlib-resources = [ - {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, - {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -itsdangerous = [ - {file = "itsdangerous-2.1.1-py3-none-any.whl", hash = "sha256:935642cd4b987cdbee7210080004033af76306757ff8b4c0a506a4b6e06f02cf"}, - {file = "itsdangerous-2.1.1.tar.gz", hash = "sha256:7b7d3023cd35d9cb0c1fd91392f8c95c6fa02c59bf8ad64b8849be3401b95afb"}, -] -jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, -] -lazy-object-proxy = [ - {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, - {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, -] -mako = [ - {file = "Mako-1.2.0-py3-none-any.whl", hash = "sha256:23aab11fdbbb0f1051b93793a58323ff937e98e34aece1c4219675122e57e4ba"}, - {file = "Mako-1.2.0.tar.gz", hash = "sha256:9a7c7e922b87db3686210cf49d5d767033a41d4010b284e747682c92bddd8b39"}, -] -markupsafe = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, -] -marshmallow = [ - {file = "marshmallow-3.15.0-py3-none-any.whl", hash = "sha256:ff79885ed43b579782f48c251d262e062bce49c65c52412458769a4fb57ac30f"}, - {file = "marshmallow-3.15.0.tar.gz", hash = "sha256:2aaaab4f01ef4f5a011a21319af9fce17ab13bf28a026d1252adab0e035648d5"}, -] -marshmallow-sqlalchemy = [ - {file = "marshmallow-sqlalchemy-0.28.0.tar.gz", hash = "sha256:fb6b06686f38fec2ea0ec53a5ee4979219409e2b2260f9bc91e4b43105d19782"}, - {file = "marshmallow_sqlalchemy-0.28.0-py2.py3-none-any.whl", hash = "sha256:f1b977c323ac0ccc0456b15d4eb9bff413b92c72d7a165f263dc276dd3782cf4"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -mkdocs-material-extensions = [ - {file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"}, - {file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"}, -] -mypy = [ - {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, - {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, - {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"}, - {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"}, - {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"}, - {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"}, - {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"}, - {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"}, - {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"}, - {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"}, - {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"}, - {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"}, - {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"}, - {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"}, - {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"}, - {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"}, - {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"}, - {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"}, - {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"}, - {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"}, - {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"}, - {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"}, - {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -nodeenv = [ - {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, - {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, -] -pbr = [ - {file = "pbr-5.8.1-py2.py3-none-any.whl", hash = "sha256:27108648368782d07bbf1cb468ad2e2eeef29086affd14087a6d04b7de8af4ec"}, - {file = "pbr-5.8.1.tar.gz", hash = "sha256:66bc5a34912f408bb3925bf21231cb6f59206267b7f63f3503ef865c1a292e25"}, -] -platformdirs = [ - {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, - {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -pre-commit = [ - {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"}, - {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pydocstyle = [ - {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"}, - {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"}, -] -pygments = [ - {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"}, - {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, -] -pylint = [ - {file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"}, - {file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"}, -] -pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, -] -pytest = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, -] -pytest-cov = [ - {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, - {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, -] -pytest-html = [ - {file = "pytest-html-3.1.1.tar.gz", hash = "sha256:3ee1cf319c913d19fe53aeb0bc400e7b0bc2dbeb477553733db1dad12eb75ee3"}, - {file = "pytest_html-3.1.1-py3-none-any.whl", hash = "sha256:b7f82f123936a3f4d2950bc993c2c1ca09ce262c9ae12f9ac763a2401380b455"}, -] -pytest-metadata = [ - {file = "pytest-metadata-1.11.0.tar.gz", hash = "sha256:71b506d49d34e539cc3cfdb7ce2c5f072bea5c953320002c95968e0238f8ecf1"}, - {file = "pytest_metadata-1.11.0-py2.py3-none-any.whl", hash = "sha256:576055b8336dd4a9006dd2a47615f76f2f8c30ab12b1b1c039d99e834583523f"}, -] -pyupgrade = [ - {file = "pyupgrade-2.31.1-py2.py3-none-any.whl", hash = "sha256:4060a7c20c79d373a3dcf34566b275c6de6cd2b034ad22465d3263fb0de82648"}, - {file = "pyupgrade-2.31.1.tar.gz", hash = "sha256:22e0ad6dd39c4381805cb059f1e691b6315c62c0ebcec98a5f29d22cd186a72a"}, -] -pyyaml = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] -rich = [ - {file = "rich-10.16.2-py3-none-any.whl", hash = "sha256:c59d73bd804c90f747c8d7b1d023b88f2a9ac2454224a4aeaf959b21eeb42d03"}, - {file = "rich-10.16.2.tar.gz", hash = "sha256:720974689960e06c2efdb54327f8bf0cdbdf4eae4ad73b6c94213cad405c371b"}, -] -safety = [ - {file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"}, - {file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"}, -] -shellingham = [ - {file = "shellingham-1.4.0-py2.py3-none-any.whl", hash = "sha256:536b67a0697f2e4af32ab176c00a50ac2899c5a05e0d8e2dadac8e58888283f9"}, - {file = "shellingham-1.4.0.tar.gz", hash = "sha256:4855c2458d6904829bd34c299f11fdeed7cfefbf8a2c522e4caea6cd76b3171e"}, -] -shopyo = [ - {file = "shopyo-4.2.1.tar.gz", hash = "sha256:f98f7285f07eb9ad728a74977c67a542588550b8f17fe867d2ee67cfeff8b6b0"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -smmap = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, -] -snowballstemmer = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] -sqlalchemy = [ - {file = "SQLAlchemy-1.4.32-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4b2bcab3a914715d332ca783e9bda13bc570d8b9ef087563210ba63082c18c16"}, - {file = "SQLAlchemy-1.4.32-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:159c2f69dd6efd28e894f261ffca1100690f28210f34cfcd70b895e0ea7a64f3"}, - {file = "SQLAlchemy-1.4.32-cp27-cp27m-win_amd64.whl", hash = "sha256:d7e483f4791fbda60e23926b098702340504f7684ce7e1fd2c1bf02029288423"}, - {file = "SQLAlchemy-1.4.32-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4aa96e957141006181ca58e792e900ee511085b8dae06c2d08c00f108280fb8a"}, - {file = "SQLAlchemy-1.4.32-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:576684771456d02e24078047c2567025f2011977aa342063468577d94e194b00"}, - {file = "SQLAlchemy-1.4.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff677fa4522dafb5a5e2c0cf909790d5d367326321aeabc0dffc9047cb235bd"}, - {file = "SQLAlchemy-1.4.32-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8679f9aba5ac22e7bce54ccd8a77641d3aea3e2d96e73e4356c887ebf8ff1082"}, - {file = "SQLAlchemy-1.4.32-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7046f7aa2db445daccc8424f50b47a66c4039c9f058246b43796aa818f8b751"}, - {file = "SQLAlchemy-1.4.32-cp310-cp310-win32.whl", hash = "sha256:bedd89c34ab62565d44745212814e4b57ef1c24ad4af9b29c504ce40f0dc6558"}, - {file = "SQLAlchemy-1.4.32-cp310-cp310-win_amd64.whl", hash = "sha256:199dc6d0068753b6a8c0bd3aceb86a3e782df118260ebc1fa981ea31ee054674"}, - {file = "SQLAlchemy-1.4.32-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:8e1e5d96b744a4f91163290b01045430f3f32579e46d87282449e5b14d27d4ac"}, - {file = "SQLAlchemy-1.4.32-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edfcf93fd92e2f9eef640b3a7a40db20fe3c1d7c2c74faa41424c63dead61b76"}, - {file = "SQLAlchemy-1.4.32-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04164e0063feb7aedd9d073db0fd496edb244be40d46ea1f0d8990815e4b8c34"}, - {file = "SQLAlchemy-1.4.32-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba59761c19b800bc2e1c9324da04d35ef51e4ee9621ff37534bc2290d258f71"}, - {file = "SQLAlchemy-1.4.32-cp36-cp36m-win32.whl", hash = "sha256:708973b5d9e1e441188124aaf13c121e5b03b6054c2df59b32219175a25aa13e"}, - {file = "SQLAlchemy-1.4.32-cp36-cp36m-win_amd64.whl", hash = "sha256:316270e5867566376e69a0ac738b863d41396e2b63274616817e1d34156dff0e"}, - {file = "SQLAlchemy-1.4.32-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:9a0195af6b9050c9322a97cf07514f66fe511968e623ca87b2df5e3cf6349615"}, - {file = "SQLAlchemy-1.4.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e4a3c0c3c596296b37f8427c467c8e4336dc8d50f8ed38042e8ba79507b2c9"}, - {file = "SQLAlchemy-1.4.32-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bca714d831e5b8860c3ab134c93aec63d1a4f493bed20084f54e3ce9f0a3bf99"}, - {file = "SQLAlchemy-1.4.32-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9a680d9665f88346ed339888781f5236347933906c5a56348abb8261282ec48"}, - {file = "SQLAlchemy-1.4.32-cp37-cp37m-win32.whl", hash = "sha256:9cb5698c896fa72f88e7ef04ef62572faf56809093180771d9be8d9f2e264a13"}, - {file = "SQLAlchemy-1.4.32-cp37-cp37m-win_amd64.whl", hash = "sha256:8b9a395122770a6f08ebfd0321546d7379f43505882c7419d7886856a07caa13"}, - {file = "SQLAlchemy-1.4.32-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:3f88a4ee192142eeed3fe173f673ea6ab1f5a863810a9d85dbf6c67a9bd08f97"}, - {file = "SQLAlchemy-1.4.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd93162615870c976dba43963a24bb418b28448fef584f30755990c134a06a55"}, - {file = "SQLAlchemy-1.4.32-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5a2e73508f939175363d8a4be9dcdc84cf16a92578d7fa86e6e4ca0e6b3667b2"}, - {file = "SQLAlchemy-1.4.32-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfec934aac7f9fa95fc82147a4ba5db0a8bdc4ebf1e33b585ab8860beb10232f"}, - {file = "SQLAlchemy-1.4.32-cp38-cp38-win32.whl", hash = "sha256:bb42f9b259c33662c6a9b866012f6908a91731a419e69304e1261ba3ab87b8d1"}, - {file = "SQLAlchemy-1.4.32-cp38-cp38-win_amd64.whl", hash = "sha256:7ff72b3cc9242d1a1c9b84bd945907bf174d74fc2519efe6184d6390a8df478b"}, - {file = "SQLAlchemy-1.4.32-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5dc9801ae9884e822ba942ca493642fb50f049c06b6dbe3178691fce48ceb089"}, - {file = "SQLAlchemy-1.4.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4607d2d16330757818c9d6fba322c2e80b4b112ff24295d1343a80b876eb0ed"}, - {file = "SQLAlchemy-1.4.32-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:20e9eba7fd86ef52e0df25bea83b8b518dfdf0bce09b336cfe51671f52aaaa3f"}, - {file = "SQLAlchemy-1.4.32-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:290cbdf19129ae520d4bdce392648c6fcdbee763bc8f750b53a5ab51880cb9c9"}, - {file = "SQLAlchemy-1.4.32-cp39-cp39-win32.whl", hash = "sha256:1bbac3e8293b34c4403d297e21e8f10d2a57756b75cff101dc62186adec725f5"}, - {file = "SQLAlchemy-1.4.32-cp39-cp39-win_amd64.whl", hash = "sha256:b3f1d9b3aa09ab9adc7f8c4b40fc3e081eb903054c9a6f9ae1633fe15ae503b4"}, - {file = "SQLAlchemy-1.4.32.tar.gz", hash = "sha256:6fdd2dc5931daab778c2b65b03df6ae68376e028a3098eb624d0909d999885bc"}, -] -stevedore = [ - {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"}, - {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"}, -] -tokenize-rt = [ - {file = "tokenize_rt-4.2.1-py2.py3-none-any.whl", hash = "sha256:08a27fa032a81cf45e8858d0ac706004fcd523e8463415ddf1442be38e204ea8"}, - {file = "tokenize_rt-4.2.1.tar.gz", hash = "sha256:0d4f69026fed520f8a1e0103aa36c406ef4661417f20ca643f913e33531b3b94"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] -typed-ast = [ - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, - {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, - {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, - {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, - {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, - {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, - {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, - {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, - {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, - {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, -] -typer = [ - {file = "typer-0.4.0-py3-none-any.whl", hash = "sha256:d81169725140423d072df464cad1ff25ee154ef381aaf5b8225352ea187ca338"}, - {file = "typer-0.4.0.tar.gz", hash = "sha256:63c3aeab0549750ffe40da79a1b524f60e08a2cbc3126c520ebf2eeaf507f5dd"}, -] -typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, -] -urllib3 = [ - {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, - {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, -] -virtualenv = [ - {file = "virtualenv-20.13.4-py2.py3-none-any.whl", hash = "sha256:c3e01300fb8495bc00ed70741f5271fc95fed067eb7106297be73d30879af60c"}, - {file = "virtualenv-20.13.4.tar.gz", hash = "sha256:ce8901d3bbf3b90393498187f2d56797a8a452fb2d0d7efc6fd837554d6f679c"}, -] -werkzeug = [ - {file = "Werkzeug-2.0.3-py3-none-any.whl", hash = "sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8"}, - {file = "Werkzeug-2.0.3.tar.gz", hash = "sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"}, -] -wrapt = [ - {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, - {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, - {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, - {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, - {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, - {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, - {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, - {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, - {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, - {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, - {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, - {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, - {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, - {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, - {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, - {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, - {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, - {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, - {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, -] -wtforms = [ - {file = "WTForms-3.0.1-py3-none-any.whl", hash = "sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b"}, - {file = "WTForms-3.0.1.tar.gz", hash = "sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc"}, -] -zipp = [ - {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"}, - {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"}, -] diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 6462618..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,152 +0,0 @@ -# Poetry pyproject.toml: https://python-poetry.org/docs/pyproject/ -[build-system] -requires = ["poetry_core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.poetry] -name = "pythoncms" -version = "0.1.0" -description = "Python CMS is an easy-to-use, instant-operations CMS" -readme = "README.md" -authors = ["shopyo "] -license = "MIT" -repository = "https://github.com/shopyo/pythoncms" -homepage = "https://github.com/shopyo/pythoncms" - -# Keywords description https://python-poetry.org/docs/pyproject/#keywords -keywords = [] #! Update me - -# Pypi classifiers: https://pypi.org/classifiers/ -classifiers = [ #! Update me - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Operating System :: OS Independent", - "Topic :: Software Development :: Libraries :: Python Modules", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", -] -packages = [ - { include = "src" }, -] - -[tool.poetry.scripts] -# Entry points for the package https://python-poetry.org/docs/pyproject/#scripts -# "pythoncms" = "pythoncms.__main__:app" - -[tool.poetry.dependencies] -python = "^3.7" -importlib_metadata = {version = "^4.5.0", python = "<3.8"} -typer = {extras = ["all"], version = "^0.4.0"} -rich = "^10.14.0" -shopyo = "4.2.1" - -[tool.poetry.dev-dependencies] -bandit = "^1.7.1" -black = {version = "^21.10b0", allow-prereleases = true} -darglint = "^1.8.1" -isort = {extras = ["colors"], version = "^5.10.1"} -mypy = "^0.910" -mypy-extensions = "^0.4.3" -pre-commit = "^2.15.0" -pydocstyle = "^6.1.1" -pylint = "^2.11.1" -pytest = "^6.2.5" -pyupgrade = "^2.29.1" -safety = "^1.10.3" -coverage = "^6.1.2" -coverage-badge = "^1.1.0" -pytest-html = "^3.1.1" -pytest-cov = "^3.0.0" - -[tool.black] -# https://github.com/psf/black -target-version = ["py37"] -line-length = 88 -color = true - -exclude = ''' -/( - \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - | env - | venv -)/ -''' - -[tool.isort] -# https://github.com/timothycrosley/isort/ -py_version = 37 -line_length = 88 - -known_typing = ["typing", "types", "typing_extensions", "mypy", "mypy_extensions"] -sections = ["FUTURE", "TYPING", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] -include_trailing_comma = true -profile = "black" -multi_line_output = 3 -indent = 4 -color_output = true -force_single_line = true - -[tool.mypy] -# https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file -python_version = 3.7 -pretty = true -show_traceback = true -color_output = true - -allow_redefinition = false -check_untyped_defs = true -disallow_any_generics = true -disallow_incomplete_defs = true -ignore_missing_imports = true -implicit_reexport = false -no_implicit_optional = true -show_column_numbers = true -show_error_codes = true -show_error_context = true -strict_equality = true -strict_optional = true -warn_no_return = true -warn_redundant_casts = true -warn_return_any = true -warn_unreachable = true -warn_unused_configs = true -warn_unused_ignores = true - - -[tool.pytest.ini_options] -# https://docs.pytest.org/en/6.2.x/customize.html#pyproject-toml -# Directories that are not visited by pytest collector: -norecursedirs =["hooks", "*.egg", ".eggs", "dist", "build", "docs", ".tox", ".git", "__pycache__"] -doctest_optionflags = ["NUMBER", "NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAIL"] - -# Extra options: -addopts = [ - "--strict-markers", - "--tb=short", - "--doctest-modules", - "--doctest-continue-on-failure", -] - -[tool.coverage.run] -source = ["tests"] - -[coverage.paths] -source = "src" - -[coverage.run] -branch = true - -[coverage.report] -fail_under = 50 -show_missing = true diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..52cf798 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +env_files = + .test.prod.env diff --git a/src/.test.prod.env b/pythoncms/.test.prod.env similarity index 100% rename from src/.test.prod.env rename to pythoncms/.test.prod.env diff --git a/pythoncms/CHANGELOG.md b/pythoncms/CHANGELOG.md new file mode 100644 index 0000000..846caba --- /dev/null +++ b/pythoncms/CHANGELOG.md @@ -0,0 +1,242 @@ +## Unreleased + +### Refactor + +- move email from auth to api (#89) +- create assets folder + +### Fix + +- tests +- tests + +## v4.2.0 (2021-11-24) + +## v4.1.3 (2021-10-26) + +### Feat + +- added commitizen to repo + +### Fix + +- clear migrations folder +- add no-action flag +- clear migrations folder +- Improve homepage wording +- Improve homepage wording + +## v4.1.2 (2021-05-19) + +### Fix + +- version +- version +- style +- test syntax +- test for new command +- test for new command +- new command: shopyo.png +- Set logo to shopyo.png +- Set logo to shopyo.png +- auto create config +- adding FLASK_APP is causing importError which causes shopyo initialise to fail. Commented that part for now +- collecstatic args not consistent with collectstatic +- tests +- collecstatic args not consistent with collectstatic +- sqlalchemy issue +- path bug +- path bug +- merge + +### Feat + +- api.templates.yo_render +- api.templates.yo_render +- cli.py is added +that allows users to add their own project command + +### Refactor + +- use click for cli instead of argv parsing +- add the shopyo info message before each command +- rename files and commmands +- delete unused files +- remove commented out code +- new command comaplete. +- update manage.py to match new cli +- new2 cli now added with basic tests +- add createmodule command +- add the new click command for collectstatic to replace the old on +- clean and write the shopyo initialise cmd +- use click for cli insteade of argv parsing + +## v3.9.0 (2021-03-01) + +### Fix + +- new project README +- init docs +- api.init -> init +- errors +- errors +- forgot to commit pytest.ini file +- local workflow - pull_request +- local workflow +- local workflow +- rm files +- tests failing +- stable +- add shopyo as req +- virtual env not needed for new command +- README +- new command +- PR #396 tests failing and code not compiling. +- Added old admin module as appadmin +- all tests passing +- style +- 124 passing +- not redirect for login +- remove testing endpoint checks +- add flask-admin to requirements +- remove requests package +- remove requests package requests package removed from requirements.txt and dev_requirements.txt fixes #383 +- use thread join for testing send_async_email +- unused imports +- unreacheableline +- env now reads from json +- added get_self_static in module help +- docs + black +- flake8 and alerts where possible +- #340 merge caused unable to compile code now fixed +- running test does not clear shopyo.db +- theme path in theme/view.py +- running test does not clear shopyo.db +- lint +- login to auth renaming +- themes to static folder +- remove coverage report command as not needed +- error in the coverage run command +- linting errors +- added panel-control for back theme +- Added front theme in front folder (themes/front/...) +- remove theme info from app.py +- delete category name with hyphen(-) +- add check for anonymous user; correct flash message +- add check for anonymous user; correct flash message +- scrolling for long content +- failing test +- review issues with branch +- style errors +- replace pycodestyle with flake8 +- add the SERVER_NAME in test config to allow url_for to be used +- add the SERVER_NAME in test config to allow url_for to be used without errors +- update tox to fix test warning. add tox to dev_requirements +- update tox to fix test warning. add tox to dev_requirements + +### Refactor + +- use intance folder or .env to hide secrets +- use intance folder or .env to hide secrets +- separate requirements.txt and dev_requirements.txt +- separate requirements.txt and dev_requirements.txt +- update clean cmd arg and add tests +- update clean cmd arg and add tests +- readable tests for category module +- readable tests for category module +- admin test with less code and easier to read +- admin test with less code and easier to read +- change the name of crud db model +- change the name of crud db model +- add the crud helper class for admin models +- add the crud helper class for admin models + +### Feat + +- rm ecommerce +- rm ecommerce +- add email confirmation disable option in configs +- add email confirmation disable option in configs +- add email confirmation +- add email confirmation +- added uploads protocol +- collectstatic command +- announcement module completed +- add CRUD DB methods and other DB utilities +- add CRUD DB model and other DB utilities + +## v3.3.6 (2021-01-09) + +### Fix + +- #221 message not flashing after contact form submit +- please login for access using shopyo notifications +- still delete category bug. closes #234 +- modified requirements.txt path for setup.py +- change import statement layout, update travis +- remove the deprecaited yield fixture call causing warning +- partial alerts +- partial alerts +- merge conflict on 2nd commit of previous branch +- tests +- correct the linting +- dev_requriements.txt was misspelled in .travis.yml +- sphinx build command should be before changing directory +- marshmallow_sqlalchemy broken in python 3.5. Removing python 3.5 check +- dev_requriements.txt was misspelled in .travis.yml +- fixed the python linting errors +- docs +- add global.py in modules and removed dummy folder +- get_symbol_currency not found +- add missing packages in dev-requiremnts.txt +- add missing packages in dev-requiremnts.txt +- screenshot update + +## v3.0.0 (2020-12-22) + +### Fix + +- conflict +- tests +- add first name and lastname +- styles formatting +- category+subcategory+product addition+product image management, TODO: fix delete of category and subcategory +- rogue empty comment removed +- www now points to / | public facing pages can access header and footer of theme | global vars injected in one place only +- startup command +- startapp command +- picture upload optional +- product pictures completed + +## v2.0.0 (2020-11-03) + +### Fix + +- page dashboard +- page dashboard + icon colors + +## v1.2.4 (2020-10-09) + +### Refactor + +- checking module name to follow certain constraints +- checking module name to follow certain constraints + +### Feat + +- added manufacturer details in people module + +## v1.1.7 (2020-10-04) + +### Fix + +- Several of issues found on products module are fixed - enhanced +- Several of issues found on products module are fixed - enhanced +- Several of issues found on products module are fixed +- Several of issues found on products module are fixed +- 138 +- 138 + +## v1.2.0 (2020-03-29) + +## 1.0.0 (2020-03-08) diff --git a/src/__init__.py b/pythoncms/__init__.py similarity index 100% rename from src/__init__.py rename to pythoncms/__init__.py diff --git a/pythoncms/app.py b/pythoncms/app.py new file mode 100644 index 0000000..477c145 --- /dev/null +++ b/pythoncms/app.py @@ -0,0 +1,266 @@ +""" +Temporary notice: + +Need help? + +- Join the discord https://discord.com/invite/k37Ef6w +- Raise an issue https://github.com/shopyo/shopyo/issues/new/choose +- Mail maintainers https://github.com/shopyo/shopyo#-contact + +Hope it helps! We welcome all questions and even requests for walkthroughs +""" +import importlib +import os +import sys + +import jinja2 +from flask import Flask +from flask_admin import Admin +from flask_admin.menu import MenuLink +from flask_login import current_user +from shopyo.api.assets import register_devstatic +from shopyo.api.debug import is_yo_debug +from shopyo.api.file import trycopy + + +base_path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, base_path) +from config import app_config + +# from init import db +from init import load_extensions +from init import modules_path +from init import installed_packages + + +from shopyo_admin import MyAdminIndexView + + +def create_app(config_name="development"): + + global_template_variables = {} + global_configs = {} + app = Flask( + __name__, + instance_path=os.path.join(base_path, "instance"), + instance_relative_config=True, + ) + + load_plugins(app, global_template_variables, global_configs, config_name) + load_config_from_obj(app, config_name) + load_config_from_instance(app, config_name) + create_config_json() + load_extensions(app) + setup_flask_admin(app) + register_devstatic(app, modules_path) + load_blueprints(app, config_name, global_template_variables, global_configs) + setup_theme_paths(app) + inject_global_vars(app, global_template_variables) + return app + + +def load_plugins(app, global_template_variables, global_configs, config_name): + for plugin in installed_packages: + if plugin not in ["shopyo_admin"]: + try: + mod = importlib.import_module(f"{plugin}.view") + app.register_blueprint(getattr(mod, f"{plugin}_blueprint")) + except AttributeError: + # print("[ ] Blueprint skipped:", e) + pass + + # global's available everywhere template vars + try: + mod_global = importlib.import_module(f"{plugin}.global") + global_template_variables.update(mod_global.available_everywhere) + except ImportError as e: + if is_yo_debug(): + print("[ ] Not loading template variable", e) + + except AttributeError as e: + if is_yo_debug(): + print("[ ] Not loading template variable", e) + + # load configs + try: + mod_global = importlib.import_module(f"{plugin}.global") + if config_name in mod_global.configs: + global_configs.update(mod_global.configs.get(config_name)) + except ImportError as e: + # print(f"[ ] {e}") + if is_yo_debug(): + print("[ ] Not loading template variable", e) + except AttributeError as e: + # click.echo('info: config not found in global') + if is_yo_debug(): + print("[ ] Not loading template variable", e) + + +def load_config_from_obj(app, config_name): + + try: + configuration = app_config[config_name] + except KeyError as e: + print( + f"[ ] Invalid config name {e}. Available configurations are: " + f"{list(app_config.keys())}\n" + ) + sys.exit(1) + + app.config.from_object(configuration) + + +def load_config_from_instance(app, config_name): + + if config_name != "testing": + # load the instance config, if it exists, when not testing + app.config.from_pyfile("config.py", silent=True) + + # create empty instance folder and empty config if not present + try: + os.makedirs(app.instance_path) + with open(os.path.join(app.instance_path, "config.py"), "a"): + pass + except OSError: + pass + + +def create_config_json(): + if not os.path.exists("config.json"): + trycopy("config_demo.json", "config.json") + + +def setup_flask_admin(app): + admin = Admin( + app, + name="My App", + template_mode="bootstrap4", + index_view=MyAdminIndexView(), + ) + # admin.add_view(DefaultModelView(Settings, db.session)) + admin.add_link(MenuLink(name="Logout", category="", url="/auth/logout?next=/admin")) + + +def load_blueprints(app, config_name, global_template_variables, global_configs): + """ + - Registers blueprints + - Adds global template objects from modules + - Adds global configs from modules + """ + for folder in os.listdir(os.path.join(base_path, "modules")): + if folder.startswith("__"): # ignore __pycache__ + continue + + if folder.startswith("box__"): + # boxes + for sub_folder in os.listdir(os.path.join(base_path, "modules", folder)): + if sub_folder.startswith("__"): # ignore __pycache__ + continue + elif sub_folder.endswith(".json"): # box_info.json + continue + try: + sys_mod = importlib.import_module( + f"modules.{folder}.{sub_folder}.view" + ) + app.register_blueprint(getattr(sys_mod, f"{sub_folder}_blueprint")) + except AttributeError: + pass + try: + mod_global = importlib.import_module( + f"modules.{folder}.{sub_folder}.global" + ) + global_template_variables.update(mod_global.available_everywhere) + except ImportError as e: + if is_yo_debug(): + print("[ ] skipped", e) + + except AttributeError as e: + if is_yo_debug(): + print("[ ] skipped", e) + + # load configs + try: + mod_global = importlib.import_module( + f"modules.{folder}.{sub_folder}.global" + ) + if config_name in mod_global.configs: + global_configs.update(mod_global.configs.get(config_name)) + except ImportError as e: + if is_yo_debug(): + print("[ ] skipped", e) + + except AttributeError as e: + # click.echo('info: config not found in global') + if is_yo_debug(): + print("[ ] skipped", e) + else: + # apps + try: + mod = importlib.import_module(f"modules.{folder}.view") + app.register_blueprint(getattr(mod, f"{folder}_blueprint")) + except AttributeError as e: + if is_yo_debug(): + print("[ ] skipped", e) + + # global's available everywhere template vars + try: + mod_global = importlib.import_module(f"modules.{folder}.global") + global_template_variables.update(mod_global.available_everywhere) + except ImportError as e: + # print(f"[ ] {e}") + if is_yo_debug(): + print("[ ] skipped", e) + + except AttributeError as e: + if is_yo_debug(): + print("[ ] skipped", e) + + # load configs + try: + mod_global = importlib.import_module(f"modules.{folder}.global") + if config_name in mod_global.configs: + global_configs.update(mod_global.configs.get(config_name)) + except ImportError as e: + # print(f"[ ] {e}") + if is_yo_debug(): + print("[ ] skipped", e) + except AttributeError as e: + # click.echo('info: config not found in global') + if is_yo_debug(): + print("[ ] skipped", e) + + app.config.update(**global_configs) + + +def setup_theme_paths(app): + with app.app_context(): + front_theme_dir = os.path.join( + app.config["BASE_DIR"], "static", "themes", "front" + ) + back_theme_dir = os.path.join( + app.config["BASE_DIR"], "static", "themes", "back" + ) + + if os.path.exists(front_theme_dir) and os.path.exists(back_theme_dir): + my_loader = jinja2.ChoiceLoader( + [ + app.jinja_loader, + jinja2.FileSystemLoader([front_theme_dir, back_theme_dir]), + ] + ) + app.jinja_loader = my_loader + + +def inject_global_vars(app, global_template_variables): + @app.context_processor + def inject_global_vars(): + APP_NAME = "dwdwefw" + + base_context = { + "APP_NAME": APP_NAME, + "len": len, + "current_user": current_user, + } + base_context.update(global_template_variables) + + return base_context diff --git a/src/autoapp.py b/pythoncms/autoapp.py.example similarity index 95% rename from src/autoapp.py rename to pythoncms/autoapp.py.example index 3283cb7..401d87a 100644 --- a/src/autoapp.py +++ b/pythoncms/autoapp.py.example @@ -1,6 +1,10 @@ +import os +import sys + sys.path.append(os.getcwd()) from app import create_app + # CONFIG_JSON_PATH = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/cli.py b/pythoncms/cli.py similarity index 74% rename from src/cli.py rename to pythoncms/cli.py index ae3e6b4..1f9d874 100644 --- a/src/cli.py +++ b/pythoncms/cli.py @@ -7,16 +7,15 @@ which contains the entry point to this file before being able to run your custom commands -Usage ``src [OPTIONS] COMMAND [ARGS]...`` +Usage ``pythoncms [OPTIONS] COMMAND [ARGS]...`` Example command 'welcome' has been added. -- To get your project version, run ``src --version`` -- Run the sample command as ``src welcome [OPTIONS] NAME`` +- To get your project version, run ``pythoncms --version`` +- Run the sample command as ``pythoncms welcome [OPTIONS] NAME`` """ - import click -from src import __version__ +from pythoncms import __version__ @click.group() @@ -35,7 +34,7 @@ def welcome(name, verbose): NAME will be printed along with the welcome message """ - click.secho(f"Hi {name}. Welcome to src", fg="cyan") + click.secho(f"Hi {name}. Welcome to pythoncms", fg="cyan") if verbose: click.echo("See you soon") diff --git a/src/config.py b/pythoncms/config.py similarity index 90% rename from src/config.py rename to pythoncms/config.py index a0ea8e4..7c47a0d 100644 --- a/src/config.py +++ b/pythoncms/config.py @@ -1,3 +1,19 @@ +""" +Specify main configs here + +Other configs are specified in module's global.py in like +configs = { + "development": { + "CONFIG_VAR": "DEVVALUE" + }, + "production": { + "CONFIG_VAR": "PRODVALUE" + }, + "testing": { + "CONFIG_VAR": "TESTVALUE" + } +} +""" import os base_path = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/config_demo.json b/pythoncms/config_demo.json similarity index 100% rename from src/config_demo.json rename to pythoncms/config_demo.json diff --git a/src/conftest.py b/pythoncms/conftest.py similarity index 76% rename from src/conftest.py rename to pythoncms/conftest.py index f878f78..d97788f 100644 --- a/src/conftest.py +++ b/pythoncms/conftest.py @@ -8,12 +8,13 @@ import os import pytest -from flask import url_for - from app import create_app +from flask import url_for +from flask_login import current_user as _current_user from init import db as _db from modules.box__default.auth.models import User from modules.box__default.settings.models import Settings +from sqlalchemy import event # run in shopyo/shopyo # python -m pytest . or python -m pytest -v @@ -67,6 +68,19 @@ def flask_app(): return flask_app +@pytest.fixture(scope="session") +def app(request): + """ + Returns session-wide application. + """ + return create_app("testing") + + +@pytest.fixture(scope="session") +def current_user(): + return _current_user + + @pytest.fixture(scope="session") def test_client(flask_app): """ @@ -120,7 +134,10 @@ def db_session(db): connection = db.engine.connect() transaction = connection.begin() options = dict(bind=connection, binds={}) - session = db.create_scoped_session(options=options) + try: + session = db._make_scoped_session(options=options) + except: + session = db.create_scoped_session(options=options) db.session = session yield session @@ -130,6 +147,41 @@ def db_session(db): session.remove() +# @pytest.fixture(scope="function", autouse=True) +# def db_session(app, db, request): +# """ +# Returns function-scoped session. +# """ +# with app.app_context(): +# conn = _db.engine.connect() +# txn = conn.begin() + +# options = dict(bind=conn, binds={}) +# sess = _db.create_scoped_session(options=options) + +# # establish a SAVEPOINT just before beginning the test +# # (http://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#using-savepoint) +# sess.begin_nested() + +# @event.listens_for(sess(), "after_transaction_end") +# def restart_savepoint(sess2, trans): +# # Detecting whether this is indeed the nested transaction of the test +# if trans.nested and not trans._parent.nested: +# # The test should have normally called session.commit(), +# # but to be safe we explicitly expire the session +# sess2.expire_all() +# sess.begin_nested() + +# _db.session = sess +# yield sess + +# # Cleanup +# sess.remove() +# # This instruction rollsback any commit that were executed in the tests. +# txn.rollback() +# conn.close() + + @pytest.fixture def login_unconfirmed_user(auth, unconfirmed_user): """Login with unconfirmed and logout during teadown""" diff --git a/src/init.py b/pythoncms/init.py similarity index 63% rename from src/init.py rename to pythoncms/init.py index 7f375f5..bc00897 100644 --- a/src/init.py +++ b/pythoncms/init.py @@ -5,19 +5,32 @@ from flask_login import LoginManager from flask_mailman import Mail -from flask_marshmallow import Marshmallow from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy from flask_wtf.csrf import CSRFProtect +# from flask_marshmallow import Marshmallow, uncommented as not updated to support flask 2.x + root_path = os.path.dirname(os.path.abspath(__file__)) # don't remove static_path = os.path.join(root_path, "static") # don't remove modules_path = os.path.join(root_path, "modules") # don't remove themes_path = os.path.join(static_path, "themes") # don't remove +installed_packages = [] # don't remove + +installed_packages = [] db = SQLAlchemy() -ma = Marshmallow() +# ma = Marshmallow() login_manager = LoginManager() migrate = Migrate() mail = Mail() csrf = CSRFProtect() + + +def load_extensions(app): + migrate.init_app(app, db) + db.init_app(app) + # ma.init_app(app) + mail.init_app(app) + login_manager.init_app(app) + csrf.init_app(app) diff --git a/src/manage.py b/pythoncms/manage.py similarity index 100% rename from src/manage.py rename to pythoncms/manage.py diff --git a/pythoncms/migrations/README b/pythoncms/migrations/README new file mode 100644 index 0000000..0e04844 --- /dev/null +++ b/pythoncms/migrations/README @@ -0,0 +1 @@ +Single-database configuration for Flask. diff --git a/pythoncms/migrations/alembic.ini b/pythoncms/migrations/alembic.ini new file mode 100644 index 0000000..ec9d45c --- /dev/null +++ b/pythoncms/migrations/alembic.ini @@ -0,0 +1,50 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic,flask_migrate + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[logger_flask_migrate] +level = INFO +handlers = +qualname = flask_migrate + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/pythoncms/migrations/env.py b/pythoncms/migrations/env.py new file mode 100644 index 0000000..a67b8d3 --- /dev/null +++ b/pythoncms/migrations/env.py @@ -0,0 +1,99 @@ +import logging +from logging.config import fileConfig + +from alembic import context +from flask import current_app + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger("alembic.env") + + +def get_engine(): + try: + # this works with Flask-SQLAlchemy<3 and Alchemical + return current_app.extensions["migrate"].db.get_engine() + except TypeError: + # this works with Flask-SQLAlchemy>=3 + return current_app.extensions["migrate"].db.engine + + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option("sqlalchemy.url", str(get_engine().url).replace("%", "%%")) +target_db = current_app.extensions["migrate"].db + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def get_metadata(): + if hasattr(target_db, "metadatas"): + return target_db.metadatas[None] + return target_db.metadata + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure(url=url, target_metadata=get_metadata(), literal_binds=True) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, "autogenerate", False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info("No changes in schema detected.") + + connectable = get_engine() + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=get_metadata(), + process_revision_directives=process_revision_directives, + **current_app.extensions["migrate"].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/pythoncms/migrations/script.py.mako b/pythoncms/migrations/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/pythoncms/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/pythoncms/migrations/versions/cb42bf1aaf17_.py b/pythoncms/migrations/versions/cb42bf1aaf17_.py new file mode 100644 index 0000000..689413d --- /dev/null +++ b/pythoncms/migrations/versions/cb42bf1aaf17_.py @@ -0,0 +1,84 @@ +"""empty message + +Revision ID: cb42bf1aaf17 +Revises: +Create Date: 2023-01-31 14:33:16.799110 + +""" +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "cb42bf1aaf17" +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "i18n_records", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("strid", sa.String(length=1024), nullable=True), + sa.Column("lang", sa.String(length=10), nullable=True), + sa.Column("string", sa.Text(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "pages", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("created_date", sa.DateTime(), nullable=True), + sa.Column("title", sa.String(length=100), nullable=True), + sa.Column("slug", sa.String(length=100), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "roles", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.String(length=100), nullable=False), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "settings", + sa.Column("setting", sa.String(length=100), nullable=False), + sa.Column("value", sa.String(length=100), nullable=True), + sa.PrimaryKeyConstraint("setting"), + ) + op.create_table( + "users", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("username", sa.String(length=100), nullable=True), + sa.Column("_password", sa.String(length=128), nullable=False), + sa.Column("first_name", sa.String(length=128), nullable=True), + sa.Column("last_name", sa.String(length=128), nullable=True), + sa.Column("is_admin", sa.Boolean(), nullable=True), + sa.Column("email", sa.String(length=120), nullable=False), + sa.Column("date_registered", sa.DateTime(), nullable=False), + sa.Column("is_email_confirmed", sa.Boolean(), nullable=False), + sa.Column("email_confirm_date", sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("email"), + sa.UniqueConstraint("username"), + ) + op.create_table( + "role_user_bridge", + sa.Column("user_id", sa.Integer(), nullable=False), + sa.Column("role_id", sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(["role_id"], ["roles.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("user_id", "role_id"), + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("role_user_bridge") + op.drop_table("users") + op.drop_table("settings") + op.drop_table("roles") + op.drop_table("pages") + op.drop_table("i18n_records") + # ### end Alembic commands ### diff --git a/src/modules/__init__.py b/pythoncms/modules/__init__.py similarity index 100% rename from src/modules/__init__.py rename to pythoncms/modules/__init__.py diff --git a/src/modules/box__bizhelp/appointment/__init__.py b/pythoncms/modules/box__default/appadmin/__init__.py similarity index 100% rename from src/modules/box__bizhelp/appointment/__init__.py rename to pythoncms/modules/box__default/appadmin/__init__.py diff --git a/src/modules/box__default/appadmin/admin.py b/pythoncms/modules/box__default/appadmin/admin.py similarity index 75% rename from src/modules/box__default/appadmin/admin.py rename to pythoncms/modules/box__default/appadmin/admin.py index 8667098..4bfba91 100644 --- a/src/modules/box__default/appadmin/admin.py +++ b/pythoncms/modules/box__default/appadmin/admin.py @@ -1,13 +1,10 @@ from functools import wraps -from flask import flash from flask import redirect -from flask import url_for from flask_login import current_user -from shopyo.api.html import notify_warning - from init import login_manager from modules.box__default.auth.models import User +from shopyo.api.html import notify_warning login_manager.login_view = "auth.login" login_manager.login_message = notify_warning("Please login for access") @@ -24,7 +21,7 @@ def wrap(*args, **kwargs): if current_user.is_admin: return f(*args, **kwargs) else: - flash(notify_warning("You need to be an admin to view this page.")) - return redirect(url_for("dashboard.index")) + + return redirect("/") return wrap diff --git a/src/modules/box__default/appadmin/info.json b/pythoncms/modules/box__default/appadmin/info.json similarity index 89% rename from src/modules/box__default/appadmin/info.json rename to pythoncms/modules/box__default/appadmin/info.json index 9921c6d..67d6f74 100644 --- a/src/modules/box__default/appadmin/info.json +++ b/pythoncms/modules/box__default/appadmin/info.json @@ -3,6 +3,7 @@ "type": "show", "fa-icon": "fas fa-user-lock", "url_prefix": "/appadmin", + "module_name": "appadmin", "author": { "name":"Abdur-Rahmaan Janhangeer", "website":"https://www.pythonkitchen.com/about-me/", diff --git a/src/modules/box__default/appadmin/models.py b/pythoncms/modules/box__default/appadmin/models.py similarity index 100% rename from src/modules/box__default/appadmin/models.py rename to pythoncms/modules/box__default/appadmin/models.py diff --git a/src/modules/box__default/appadmin/templates/appadmin/add.html b/pythoncms/modules/box__default/appadmin/templates/appadmin/add.html similarity index 100% rename from src/modules/box__default/appadmin/templates/appadmin/add.html rename to pythoncms/modules/box__default/appadmin/templates/appadmin/add.html diff --git a/src/modules/box__default/appadmin/templates/appadmin/blocks/sidebar.html b/pythoncms/modules/box__default/appadmin/templates/appadmin/blocks/sidebar.html similarity index 100% rename from src/modules/box__default/appadmin/templates/appadmin/blocks/sidebar.html rename to pythoncms/modules/box__default/appadmin/templates/appadmin/blocks/sidebar.html diff --git a/src/modules/box__default/appadmin/templates/appadmin/edit.html b/pythoncms/modules/box__default/appadmin/templates/appadmin/edit.html similarity index 100% rename from src/modules/box__default/appadmin/templates/appadmin/edit.html rename to pythoncms/modules/box__default/appadmin/templates/appadmin/edit.html diff --git a/src/modules/box__default/appadmin/templates/appadmin/index.html b/pythoncms/modules/box__default/appadmin/templates/appadmin/index.html similarity index 100% rename from src/modules/box__default/appadmin/templates/appadmin/index.html rename to pythoncms/modules/box__default/appadmin/templates/appadmin/index.html diff --git a/src/modules/box__default/appadmin/templates/appadmin/roles.html b/pythoncms/modules/box__default/appadmin/templates/appadmin/roles.html similarity index 100% rename from src/modules/box__default/appadmin/templates/appadmin/roles.html rename to pythoncms/modules/box__default/appadmin/templates/appadmin/roles.html diff --git a/pythoncms/modules/box__default/appadmin/tests/test_admin.py b/pythoncms/modules/box__default/appadmin/tests/test_admin.py new file mode 100644 index 0000000..14906b5 --- /dev/null +++ b/pythoncms/modules/box__default/appadmin/tests/test_admin.py @@ -0,0 +1,405 @@ +""" +This file (test_admin.py) contains the functional tests for +the `admin` blueprint. + +These tests use GETs and POSTs to different endpoints to check +for the proper behavior of the `admin` blueprint. +""" +import json +import os + +import pytest +from flask import request +from flask import url_for +from modules.box__default.auth.models import Role +from modules.box__default.auth.models import role_user_bridge +from modules.box__default.auth.models import User + + +dirpath = os.path.dirname(os.path.abspath(__file__)) +module_path = os.path.dirname(dirpath) + +module_info = None + + +# class TestAdminInvalidAccess: +# """ +# Test all admin routes for correct user authentication +# """ + +# routes_get = [ +# "/", +# "/add", +# "/delete/", +# "/edit/", +# "/roles", +# "/roles//delete", +# ] + +# routes_post = ["/update", "/roles/update", "/roles/add", "/add"] + +# @pytest.mark.parametrize("route", routes_get) +# def test_redirect_if_not_logged_in_get(self, test_client, route, auth): +# auth.logout() +# with open(os.path.join(module_path, "info.json")) as f: +# module_info = json.load(f) +# response = test_client.get( +# f"{module_info['url_prefix']}{route}", follow_redirects=True +# ) + +# assert response.status_code == 200 +# assert request.path == url_for("auth.login") + +# @pytest.mark.parametrize("route", routes_post) +# def test_redirect_if_not_logged_in_post(self, test_client, route, auth): +# auth.logout() +# with open(os.path.join(module_path, "info.json")) as f: +# module_info = json.load(f) +# response = test_client.post( +# f"{module_info['url_prefix']}{route}", follow_redirects=True +# ) + +# assert response.status_code == 200 +# assert request.path == url_for("auth.login") + +# @pytest.mark.usefixtures("login_non_admin_user") +# @pytest.mark.parametrize("route", routes_get) +# def test_no_admin_access_if_not_admin_get(self, test_client, route): +# with open(os.path.join(module_path, "info.json")) as f: +# module_info = json.load(f) +# response = test_client.get( +# f"{module_info['url_prefix']}{route}", follow_redirects=True +# ) + +# assert response.status_code == 200 +# assert request.path == url_for("dashboard.index") +# assert b"You need to be an admin to view this page" in response.data + +# @pytest.mark.usefixtures("login_non_admin_user") +# @pytest.mark.parametrize("route", routes_post) +# def test_no_admin_access_if_not_admin_post(self, test_client, route): +# with open(os.path.join(module_path, "info.json")) as f: +# module_info = json.load(f) +# response = test_client.post( +# f"{module_info['url_prefix']}{route}", follow_redirects=True +# ) + +# assert response.status_code == 200 +# assert request.path == url_for("dashboard.index") +# assert b"You need to be an admin to view this page" in response.data + + +@pytest.mark.usefixtures("login_admin_user") +class TestAdminEndpoints: + """ + Test all admin api post and get requests + """ + + # def test_admin_user_list_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.get(f"{module_info['url_prefix']}/") + + # assert response.status_code == 200 + # assert b"Admin" in response.data + # assert b"id" in response.data + # assert b"Email" in response.data + # assert b"Password" in response.data + # assert b"Roles" in response.data + + # def test_admin_add_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.get(f"{module_info['url_prefix']}/add") + + # assert response.status_code == 200 + # assert b"Email" in response.data + # assert b"Password" in response.data + # assert b"First Name" in response.data + # assert b"Last Name" in response.data + # assert b"Admin User" in response.data + + # def test_admin_add_unique_user_post(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # role1 = Role.create(name="test1-role") + # role2 = Role.create(name="test2-role") + # data = { + # "email": "test@gmail.com", + # "password": "pass", + # "first_name": "Test", + # "last_name": "User", + # "is_admin": "", + # f"role_{role1.id}": "", + # f"role_{role2.id}": "", + # } + + # test_client.post( + # f"{module_info['url_prefix']}/add", + # data=data, + # follow_redirects=True, + # ) + # test_user = User.query.filter(User.email == "test@gmail.com").scalar() + + # assert test_user is not None + # assert test_user.first_name == "Test" + # assert test_user.last_name == "User" + # assert test_user.is_admin is False + # assert test_user.roles is not None + # assert len(test_user.roles) == 2 + # assert role1.users[0].email == "test@gmail.com" + # assert role2.users[0].email == "test@gmail.com" + + # def test_admin_add_existing_user_post(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # User.create(email="test@gmail.com", password="pass") + # data = { + # "email": "test@gmail.com", + # "password": "pass", + # "first_name": "Test", + # "last_name": "User", + # "is_admin": "", + # } + + # response = test_client.post( + # f"{module_info['url_prefix']}/add", + # data=data, + # follow_redirects=True, + # ) + # test_users = User.query.filter(User.email == "test@gmail.com").count() + + # assert response.status_code == 200 + # assert b"User with same email already exists" in response.data + # assert test_users == 1 + + # def test_admin_delete_existing_user_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # user = User(email="test@gmail.com", password="pass") + # role1 = Role(name="test1-role") + # role2 = Role(name="test2-role") + # user.roles = [role1, role2] + # user.save() + + # response = test_client.get( + # f"{module_info['url_prefix']}/delete/{user.id}", + # follow_redirects=True, + # ) + # test_user = User.query.filter(User.email == user.email).scalar() + # test_roles = Role.query.count() + # user_role = ( + # User.query.join(role_user_bridge) + # .join(Role) + # .filter(User.id == user.id) + # .scalar() + # ) + + # assert response.status_code == 200 + # assert test_user is None + # assert user_role is None + # assert test_roles == 2 + + # def test_admin_delete_nonexisting_user_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.get( + # f"{module_info['url_prefix']}/delete/some_id", + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert b"Unable to delete. Invalid user id" in response.data + + # def test_admin_edit_existing_user_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # user = User.create(email="test@gmail.com", password="pass") + + # response = test_client.get( + # f"{module_info['url_prefix']}/edit/{user.id}", + # ) + + # assert response.status_code == 200 + # assert b"test@gmail.com" in response.data + # assert b"Edit User" in response.data + + # def test_admin_edit_nonexisting_user_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.get( + # f"{module_info['url_prefix']}/edit/some-id", follow_redirects=True + # ) + + # assert response.status_code == 200 + # assert b"Invalid user id" in response.data + # assert request.path == f"{module_info['url_prefix']}/" + + # def test_admin_update_user_adding_new_roles_to_user(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # user = User.create(email="foo@gmail.com", password="pass") + # role1 = Role.create(name="test1-role") + # role2 = Role.create(name="test2-role") + # data = { + # "id": str(user.id), + # "email": "bar@gmail.com", + # "password": "newpass", + # "first_name": "Test", + # "last_name": "User", + # "is_admin": "", + # f"role_{role1.id}": "", + # f"role_{role2.id}": "", + # } + + # response = test_client.post( + # f"{module_info['url_prefix']}/update", + # data=data, + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert user.email == "bar@gmail.com" + # assert user.check_password("newpass") + # assert user.first_name == "Test" + # assert user.last_name == "User" + # assert len(user.roles) == 2 + # assert role1.users[0].email == "bar@gmail.com" + # assert role2.users[0].email == "bar@gmail.com" + + # def test_admin_update_user_remove_old_roles_from_user(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # user = User(email="foo@gmail.com", password="pass", is_admin=True) + # user.is_admin = True + # role1 = Role(name="test1-role") + # role2 = Role(name="test2-role") + # user.roles = [role1, role2] + # user.save() + # data = { + # "id": str(user.id), + # "email": "bar@gmail.com", + # "first_name": "Test", + # "last_name": "User", + # "password": " ", + # "is_admin": None, + # } + + # response = test_client.post( + # f"{module_info['url_prefix']}/update", + # data=data, + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert user.email == "bar@gmail.com" + # assert user.check_password("pass") + # assert len(user.roles) == 0 + # assert len(role1.users) == 0 + # assert len(role2.users) == 0 + + # def test_admin_roles_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.get(f"{module_info['url_prefix']}/roles") + + # assert response.status_code == 200 + # assert b"Roles" in response.data + + # def test_admin_roles_add_nonexisting_role_post(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.post( + # f"{module_info['url_prefix']}/roles/add", + # data=dict(name="new-role"), + # follow_redirects=True, + # ) + + # role = Role.query.filter(Role.name == "new-role").scalar() + # role_count = Role.query.count() + + # assert response.status_code == 200 + # assert role is not None + # assert role_count == 1 + + # def test_admin_roles_add_existing_role_post(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # Role.create(name="new-role") + + # response = test_client.post( + # f"{module_info['url_prefix']}/roles/add", + # data=dict(name="new-role"), + # follow_redirects=True, + # ) + # role_count = Role.query.count() + # role = Role.query.filter(Role.name == "new-role").scalar() + + # assert response.status_code == 200 + # assert b"Role already exists" in response.data + # assert role is not None + # assert role_count == 1 + + # def test_admin_roles_delete_nonexisting_role_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.get( + # f"{module_info['url_prefix']}/roles/some-id/delete", + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert request.path == f"{module_info['url_prefix']}/roles" + # assert b"Unable to delete. Invalid role id" in response.data + + # def test_admin_roles_delete_existing_role_get(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # role1 = Role.create(name="new-role1") + # role2 = Role.create(name="new-role2") + + # response = test_client.get( + # f"{module_info['url_prefix']}/roles/{role1.id}/delete", + # follow_redirects=True, + # ) + # roles = Role.query.all() + + # assert response.status_code == 200 + # assert request.path == f"{module_info['url_prefix']}/roles" + # assert b"Role successfully deleted" in response.data + # assert roles is not None + # assert roles[0].name == role2.name + # assert len(roles) == 1 + + # def test_admin_roles_update_nonexisting_role_post(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # response = test_client.post( + # f"{module_info['url_prefix']}/roles/update", + # data=dict(role_id="some-id"), + # follow_redirects=True, + # ) + # roles = Role.query.count() + + # assert response.status_code == 200 + # assert request.path == f"{module_info['url_prefix']}/roles" + # assert b"Unable to update. Role does not exist" in response.data + # assert roles == 0 + + # def test_admin_roles_update_existing_role_post(self, test_client): + # with open(os.path.join(module_path, "info.json")) as f: + # module_info = json.load(f) + # new_role = Role.create(name="new-role1") + + # response = test_client.post( + # f"{module_info['url_prefix']}/roles/update", + # data=dict(role_id=new_role.id, role_name="update-role"), + # follow_redirects=True, + # ) + # role = Role.query.scalar() + + # assert response.status_code == 200 + # assert request.path == f"{module_info['url_prefix']}/roles" + # assert b"Role successfully updated" in response.data + # assert role is not None + # assert role.name == "update-role" diff --git a/src/modules/box__default/appadmin/tests/test_models.py b/pythoncms/modules/box__default/appadmin/tests/test_models.py similarity index 100% rename from src/modules/box__default/appadmin/tests/test_models.py rename to pythoncms/modules/box__default/appadmin/tests/test_models.py diff --git a/src/modules/box__default/appadmin/view.py b/pythoncms/modules/box__default/appadmin/view.py similarity index 87% rename from src/modules/box__default/appadmin/view.py rename to pythoncms/modules/box__default/appadmin/view.py index 175897c..8052567 100644 --- a/src/modules/box__default/appadmin/view.py +++ b/pythoncms/modules/box__default/appadmin/view.py @@ -3,43 +3,30 @@ :synopsis: All endpoints of the admin views are defined here. """ -import json -import os - -from flask import Blueprint from flask import flash from flask import redirect from flask import render_template from flask import request from flask import url_for from flask_login import login_required -from shopyo.api.html import notify_success -from shopyo.api.html import notify_warning -from sqlalchemy import exists - from init import db from modules.box__default.auth.models import Role from modules.box__default.auth.models import User +from shopyo.api.html import notify_success +from shopyo.api.html import notify_warning +from shopyo.api.module import ModuleHelp +from sqlalchemy import exists from .admin import admin_required # from config import Config -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} - -with open(dirpath + "/info.json") as f: - module_info = json.load(f) - -appadmin_blueprint = Blueprint( - "appadmin", - __name__, - template_folder="templates", - url_prefix=module_info["url_prefix"], -) +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] -@appadmin_blueprint.route("/") +@module_blueprint.route("/") @login_required @admin_required def user_list(): @@ -54,7 +41,7 @@ def user_list(): return render_template("appadmin/index.html", **context) -@appadmin_blueprint.route("/add", methods=["GET", "POST"]) +@module_blueprint.route("/add", methods=["GET", "POST"]) @login_required @admin_required def user_add(): @@ -100,7 +87,7 @@ def user_add(): return render_template("appadmin/add.html", **context) -@appadmin_blueprint.route("/delete/", methods=["GET"]) +@module_blueprint.route("/delete/", methods=["GET"]) @login_required @admin_required def admin_delete(id): @@ -122,7 +109,7 @@ def admin_delete(id): return redirect("/appadmin") -@appadmin_blueprint.route("/edit/", methods=["GET"]) +@module_blueprint.route("/edit/", methods=["GET"]) @login_required @admin_required def admin_edit(id): @@ -146,7 +133,7 @@ def admin_edit(id): return render_template("appadmin/edit.html", **context) -@appadmin_blueprint.route("/update", methods=["POST"]) +@module_blueprint.route("/update", methods=["POST"]) @login_required @admin_required def admin_update(): @@ -192,7 +179,7 @@ def admin_update(): return redirect("/appadmin") -@appadmin_blueprint.route("/roles") +@module_blueprint.route("/roles") @login_required @admin_required def roles(): @@ -201,7 +188,7 @@ def roles(): return render_template("appadmin/roles.html", **context) -@appadmin_blueprint.route("/roles/add", methods=["POST"]) +@module_blueprint.route("/roles/add", methods=["POST"]) @login_required @admin_required def roles_add(): @@ -215,7 +202,7 @@ def roles_add(): return redirect(url_for("appadmin.roles")) -@appadmin_blueprint.route("/roles//delete", methods=["GET"]) +@module_blueprint.route("/roles//delete", methods=["GET"]) @login_required @admin_required def roles_delete(role_id): @@ -230,7 +217,7 @@ def roles_delete(role_id): return redirect(url_for("appadmin.roles")) -@appadmin_blueprint.route("/roles/update", methods=["POST"]) +@module_blueprint.route("/roles/update", methods=["POST"]) @login_required @admin_required def roles_update(): diff --git a/src/modules/box__default/auth/decorators.py b/pythoncms/modules/box__default/auth/decorators.py similarity index 100% rename from src/modules/box__default/auth/decorators.py rename to pythoncms/modules/box__default/auth/decorators.py diff --git a/src/modules/box__default/auth/forms.py b/pythoncms/modules/box__default/auth/forms.py similarity index 100% rename from src/modules/box__default/auth/forms.py rename to pythoncms/modules/box__default/auth/forms.py diff --git a/src/modules/box__default/auth/info.json b/pythoncms/modules/box__default/auth/info.json similarity index 80% rename from src/modules/box__default/auth/info.json rename to pythoncms/modules/box__default/auth/info.json index 848d39c..b52f395 100644 --- a/src/modules/box__default/auth/info.json +++ b/pythoncms/modules/box__default/auth/info.json @@ -2,5 +2,6 @@ "display_string": "Login", "type": "hidden", "fa-icon": "fas fa-clock", + "module_name": "auth", "url_prefix": "/auth" } diff --git a/src/modules/box__default/auth/models.py b/pythoncms/modules/box__default/auth/models.py similarity index 99% rename from src/modules/box__default/auth/models.py rename to pythoncms/modules/box__default/auth/models.py index ae96088..c8113be 100644 --- a/src/modules/box__default/auth/models.py +++ b/pythoncms/modules/box__default/auth/models.py @@ -8,15 +8,14 @@ from flask import current_app from flask_login import AnonymousUserMixin from flask_login import UserMixin +from init import db +from init import login_manager from itsdangerous import URLSafeTimedSerializer from shopyo.api.models import PkModel from sqlalchemy.ext.hybrid import hybrid_property from werkzeug.security import check_password_hash from werkzeug.security import generate_password_hash -from init import db -from init import login_manager - role_user_bridge = db.Table( "role_user_bridge", db.Column( diff --git a/src/modules/box__default/auth/static/style.css b/pythoncms/modules/box__default/auth/static/style.css similarity index 100% rename from src/modules/box__default/auth/static/style.css rename to pythoncms/modules/box__default/auth/static/style.css diff --git a/src/modules/box__default/auth/templates/auth/blocks/login_form.html b/pythoncms/modules/box__default/auth/templates/auth/blocks/login_form.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/blocks/login_form.html rename to pythoncms/modules/box__default/auth/templates/auth/blocks/login_form.html diff --git a/src/modules/box__default/auth/templates/auth/blocks/register_form.html b/pythoncms/modules/box__default/auth/templates/auth/blocks/register_form.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/blocks/register_form.html rename to pythoncms/modules/box__default/auth/templates/auth/blocks/register_form.html diff --git a/src/modules/box__default/auth/templates/auth/emails/activate_user.html b/pythoncms/modules/box__default/auth/templates/auth/emails/activate_user.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/emails/activate_user.html rename to pythoncms/modules/box__default/auth/templates/auth/emails/activate_user.html diff --git a/src/modules/box__default/auth/templates/auth/emails/activate_user.txt b/pythoncms/modules/box__default/auth/templates/auth/emails/activate_user.txt similarity index 100% rename from src/modules/box__default/auth/templates/auth/emails/activate_user.txt rename to pythoncms/modules/box__default/auth/templates/auth/emails/activate_user.txt diff --git a/src/modules/box__default/auth/templates/auth/login.html b/pythoncms/modules/box__default/auth/templates/auth/login.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/login.html rename to pythoncms/modules/box__default/auth/templates/auth/login.html diff --git a/src/modules/box__default/auth/templates/auth/register.html b/pythoncms/modules/box__default/auth/templates/auth/register.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/register.html rename to pythoncms/modules/box__default/auth/templates/auth/register.html diff --git a/src/modules/box__default/auth/templates/auth/shop_login.html b/pythoncms/modules/box__default/auth/templates/auth/shop_login.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/shop_login.html rename to pythoncms/modules/box__default/auth/templates/auth/shop_login.html diff --git a/src/modules/box__default/auth/templates/auth/unconfirmed.html b/pythoncms/modules/box__default/auth/templates/auth/unconfirmed.html similarity index 100% rename from src/modules/box__default/auth/templates/auth/unconfirmed.html rename to pythoncms/modules/box__default/auth/templates/auth/unconfirmed.html diff --git a/src/modules/box__default/auth/tests/conftest.py b/pythoncms/modules/box__default/auth/tests/conftest.py similarity index 100% rename from src/modules/box__default/auth/tests/conftest.py rename to pythoncms/modules/box__default/auth/tests/conftest.py diff --git a/src/modules/box__default/auth/tests/factories.py b/pythoncms/modules/box__default/auth/tests/factories.py similarity index 99% rename from src/modules/box__default/auth/tests/factories.py rename to pythoncms/modules/box__default/auth/tests/factories.py index 8fa64e4..7e7b7fa 100644 --- a/src/modules/box__default/auth/tests/factories.py +++ b/pythoncms/modules/box__default/auth/tests/factories.py @@ -1,11 +1,10 @@ """Factories to help in tests.""" from factory import Sequence from factory.alchemy import SQLAlchemyModelFactory -from sqlalchemy.orm import scoped_session - from init import db from modules.box__default.auth.models import Role from modules.box__default.auth.models import User +from sqlalchemy.orm import scoped_session class BaseFactory(SQLAlchemyModelFactory): diff --git a/src/modules/box__default/auth/tests/test_auth_forms.py b/pythoncms/modules/box__default/auth/tests/test_auth_forms.py similarity index 100% rename from src/modules/box__default/auth/tests/test_auth_forms.py rename to pythoncms/modules/box__default/auth/tests/test_auth_forms.py diff --git a/pythoncms/modules/box__default/auth/tests/test_auth_functional.py b/pythoncms/modules/box__default/auth/tests/test_auth_functional.py new file mode 100644 index 0000000..c916339 --- /dev/null +++ b/pythoncms/modules/box__default/auth/tests/test_auth_functional.py @@ -0,0 +1,288 @@ +""" +This file (test_auth_functional.py) contains the functional tests for +the `auth` blueprint. + +These tests use GETs and POSTs to different endpoints to check +for the proper behavior of the `auth` module +""" +import json +import os +import threading + +import pytest +import sqlalchemy +from flask import request +from flask import url_for +from modules.box__default.auth.models import User + +dirpath = os.path.dirname(os.path.abspath(__file__)) +module_path = os.path.dirname(dirpath) + +module_info = None + +with open(os.path.join(module_path, "info.json")) as f: + module_info = json.load(f) + + +# class TestAuthInvalidAccess: +# """ +# Test all auth routes for correct user authentication +# """ + +# routes_get = [ +# "/confirm/", +# "/resend", +# "/unconfirmed", +# ] + +# @pytest.mark.parametrize("route", routes_get) +# def test_redirect_if_not_logged_in_get(self, test_client, route, auth): +# auth.logout() +# response = test_client.get( +# f"{module_info['url_prefix']}{route}", follow_redirects=True +# ) + +# assert response.status_code == 200 +# assert request.path == url_for("auth.login") + + +class TestAuthEndpoints: + """ + Test all auth routes' functionalities + """ + + def test_user_registration_page_renders(self, test_client): + response = test_client.get(f"{module_info['url_prefix']}/register") + + assert response.status_code == 200 + assert b"Email" in response.data + assert b"Password" in response.data + assert b"Confirm Password" in response.data + assert b"Register" in response.data + + def test_user_not_registered_on_invalid_form_submit(self, test_client): + User.create(email="test@gmail.com", password="pass") + data = { + "email": "test@gmail.com", + "password": "password", + "confirm": "password", + } + + response = test_client.post( + f"{module_info['url_prefix']}/register", + data=data, + follow_redirects=True, + ) + + assert response.status_code == 200 + assert request.path == url_for("auth.register") + + def test_user_registration_is_case_insensitive(self, test_client): + User.create(email="foo@bar.com", password="pass") + data = { + "email": "Foo@Bar.com", + "password": "password", + "confirm": "password", + } + + response = test_client.post( + f"{module_info['url_prefix']}/register", + data=data, + follow_redirects=True, + ) + + assert response.status_code == 200 + assert request.path == url_for("auth.register") + + # @pytest.mark.parametrize( + # "email_config", + # [ + # ("EMAIL_CONFIRMATION_DISABLED", True), + # ], + # indirect=True, + # ) + # def test_user_confirmed_if_email_disabled(self, test_client, email_config): + # data = { + # "email": "test@gmail.com", + # "password": "password", + # "confirm": "password", + # } + # response = test_client.post( + # f"{module_info['url_prefix']}/register", + # data=data, + # follow_redirects=True, + # ) + # user = User.query.filter(User.email == "test@gmail.com").scalar() + + # assert response.status_code == 200 + # assert request.path == url_for('auth.register') + # assert user.is_email_confirmed is True + + # @pytest.mark.parametrize( + # "email_config", + # [ + # ("EMAIL_CONFIRMATION_DISABLED", "remove"), + # ("EMAIL_CONFIRMATION_DISABLED", False), + # ("EMAIL_CONFIRMATION_DISABLED", None), + # ], + # indirect=True, + # ) + # def test_user_is_registered_on_valid_form_submit( + # self, test_client, capfd, email_config + # ): + # data = { + # "email": "test@gmail.com", + # "password": "password", + # "confirm": "password", + # } + # response = test_client.post( + # f"{module_info['url_prefix']}/register", + # data=data, + # follow_redirects=True, + # ) + # # Not very happy with this solution. Need a better + # # way to wait for the email thread to join with main + # # thread before reading the email written to stdout @rehmanis + # while threading.activeCount() > 1: + # pass + # else: + # captured = capfd.readouterr() + + # user = User.query.filter(User.email == "test@gmail.com").scalar() + + # assert response.status_code == 200 + # assert request.path == url_for("auth.unconfirmed") + # assert b"A confirmation email has been sent via email" in response.data + # assert "test@gmail.com" in captured.out + # assert "Welcome to Shopyo" in captured.out + # assert user is not None + # assert user.is_email_confirmed is False + + # @pytest.mark.usefixtures("login_non_admin_user") + # def test_user_not_confirmed_for_already_confirmed_user(self, test_client): + # response = test_client.get( + # url_for("auth.confirm", token="sometoken"), follow_redirects=True + # ) + + # assert response.status_code == 200 + # assert request.path == url_for("dashboard.index") + # assert b"Account already confirmed." in response.data + + # @pytest.mark.usefixtures("login_unconfirmed_user") + # def test_user_confirmed_on_valid_token(self, test_client, current_user): + # token = current_user.generate_confirmation_token() + # response = test_client.get( + # url_for("auth.confirm", token=token), follow_redirects=True + # ) + + # assert response.status_code == 200 + # # assert request.path == url_for("dashboard.index") + # # assert b"You have confirmed your account. Thanks!" in response.data + # assert current_user.is_email_confirmed is True + + # @pytest.mark.usefixtures("login_unconfirmed_user") + # def test_no_confirm_sent_for_invalid_token(self, test_client, current_user): + # token = current_user.generate_confirmation_token() + "extra" + # response = test_client.get( + # url_for("auth.confirm", token=token), follow_redirects=True + # ) + + # assert response.status_code == 200 + # assert request.path == url_for("auth.unconfirmed") + # assert b"The confirmation link is invalid/expired." in response.data + + # @pytest.mark.usefixtures("login_non_admin_user") + # def test_do_not_allow_email_resend_for_confirmed(self, test_client): + # response = test_client.get(url_for("auth.resend"), follow_redirects=True) + + # assert response.status_code == 200 + # assert request.path == '/' + + # @pytest.mark.usefixtures("login_unconfirmed_user") + # def test_valid_resend_email_confirmation(self, test_client, capfd, current_user): + # response = test_client.get(url_for("auth.resend"), follow_redirects=True) + + # # Not very happy with this solution. Need a better + # # way to wait for the email thread to join with main + # # thread before reading the email written to stdout @rehmanis + # while threading.activeCount() > 1: + # pass + # else: + # captured = capfd.readouterr() + + # assert response.status_code == 200 + # assert current_user.email in captured.out + # assert "Welcome to Shopyo" in captured.out + # assert request.path == url_for("auth.unconfirmed") + # assert b"A new confirmation email has been sent" in response.data + + # @pytest.mark.usefixtures("login_non_admin_user") + # def test_confirmed_user_is_redirected_to_dashboard(self, test_client): + # response = test_client.get(url_for("auth.unconfirmed"), follow_redirects=True) + + # assert response.status_code == 200 + # assert request.path == '/' + + # @pytest.mark.usefixtures("login_unconfirmed_user") + # def test_unconfirmed_page_renders_correctly(self, test_client, current_user): + # response = test_client.get(url_for("auth.unconfirmed")) + + # assert response.status_code == 302 + # assert request.path == url_for("auth.unconfirmed") + # assert b"You have not confirmed your account" in response.data + # assert b"Email confirmation link was sent to" in response.data + # assert current_user.email.encode() in response.data + + # def test_login_for_dashboard_renders(self, test_client): + # response = test_client.get(url_for("auth.login")) + + # assert response.status_code == 200 + # assert b"Login" in response.data + # assert b"submit" in response.data + + # def test_invalid_dashboard_login(self, test_client): + # response = test_client.post( + # url_for("auth.login"), + # data=dict(email="admin1@domain.com", password="wrongpass"), + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert request.path == url_for("auth.login") + # assert b"please check your user id and password" in response.data + + # def test_valid_dashboard_login(self, test_client, admin_user, current_user): + # response = test_client.post( + # url_for("auth.login"), + # data=dict(email=admin_user.email, password="pass"), + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert current_user.email == admin_user.email + # assert request.path == url_for("dashboard.index") + + # def test_valid_dashboard_login_is_case_insensitive(self, test_client, current_user): + # try: + # User.create(email="foo@bar.com", password="pass") + # except sqlalchemy.exc.IntegrityError: + # pass + # data = {"email": "Foo@Bar.com", "password": "pass"} + # response = test_client.post( + # url_for("auth.login"), + # data=data, + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert current_user.email.lower() == data["email"].lower() + # assert request.path == url_for("auth.unconfirmed") + + # @pytest.mark.usefixtures("login_non_admin_user") + # def test_current_user_logout(self, test_client, current_user): + # response = test_client.get(url_for("auth.logout"), follow_redirects=True) + + # assert response.status_code == 200 + # assert request.path == url_for("auth.login") + # assert b"Successfully logged out" in response.data + # assert current_user.is_authenticated is False diff --git a/src/modules/box__default/auth/tests/test_auth_models.py b/pythoncms/modules/box__default/auth/tests/test_auth_models.py similarity index 54% rename from src/modules/box__default/auth/tests/test_auth_models.py rename to pythoncms/modules/box__default/auth/tests/test_auth_models.py index a0a7a4c..904c508 100644 --- a/src/modules/box__default/auth/tests/test_auth_models.py +++ b/pythoncms/modules/box__default/auth/tests/test_auth_models.py @@ -6,14 +6,13 @@ import pytest from freezegun import freeze_time -from sqlalchemy.exc import IntegrityError - from modules.box__default.auth.models import AnonymousUser from modules.box__default.auth.models import Role -from modules.box__default.auth.models import User from modules.box__default.auth.models import role_user_bridge +from modules.box__default.auth.models import User from modules.box__default.auth.tests.factories import RoleFactory from modules.box__default.auth.tests.factories import UserFactory +from sqlalchemy.exc import IntegrityError class TestAuthFactory: @@ -94,84 +93,84 @@ def test_anonymous_user_representation(self): class TestUser: """Test User model""" - def test_get_user_by_id(self): - user = User.create(email="foo@bar.com", password="pass") - retrieved = User.get_by_id(user.id) + # def test_get_user_by_id(self): + # user = User.create(email="foo@bar.com", password="pass") + # retrieved = User.get_by_id(user.id) - assert retrieved == user + # assert retrieved == user - def test_email_is_unique(self): - User.create(email="foo@bar.com", password="pass") + # def test_email_is_unique(self): + # User.create(email="foo@bar.com", password="pass") - with pytest.raises(IntegrityError): - User.create(email="foo@bar.com", password="another") + # with pytest.raises(IntegrityError): + # User.create(email="foo@bar.com", password="another") - def test_username_is_unique(self): - User.create(username="foo", email="foo@bar.com", password="pass") + # def test_username_is_unique(self): + # User.create(username="foo", email="foo@bar.com", password="pass") - with pytest.raises(IntegrityError): - User.create(username="foo", email="bar@bar.com", password="pass") + # with pytest.raises(IntegrityError): + # User.create(username="foo", email="bar@bar.com", password="pass") - def test_email_is_not_nullable(self): - with pytest.raises(IntegrityError): - User.create(username="foo", password="pass") + # def test_email_is_not_nullable(self): + # with pytest.raises(IntegrityError): + # User.create(username="foo", password="pass") - def test_password_is_not_nullable(self): - with pytest.raises(IntegrityError): - User.create(username="foo") + # def test_password_is_not_nullable(self): + # with pytest.raises(IntegrityError): + # User.create(username="foo") - def test_user_is_not_admin_by_default(self): - user = User.create(email="foo@bar.com", password="pass") + # def test_user_is_not_admin_by_default(self): + # user = User.create(email="foo@bar.com", password="pass") - assert user.is_admin is False + # assert user.is_admin is False - def test_date_registered_at_defaults_to_datetime(self): - user = User.create(email="foo@bar.com", password="pass") + # def test_date_registered_at_defaults_to_datetime(self): + # user = User.create(email="foo@bar.com", password="pass") - assert bool(user.date_registered) - assert isinstance(user.date_registered, dt.datetime) + # assert bool(user.date_registered) + # assert isinstance(user.date_registered, dt.datetime) - def test_email_is_not_confirmed_by_default(self): - user = User.create(email="foo@bar.com", password="pass") + # def test_email_is_not_confirmed_by_default(self): + # user = User.create(email="foo@bar.com", password="pass") - assert user.is_email_confirmed is False + # assert user.is_email_confirmed is False - def test_check_password(self): - user = User.create(email="foo@bar.com", password="foobar123$") + # def test_check_password(self): + # user = User.create(email="foo@bar.com", password="foobar123$") - assert user.check_password("foobaz123") is False - assert user.check_password("foobar123$") + # assert user.check_password("foobaz123") is False + # assert user.check_password("foobar123$") - def test_password_hashed_on_user_creation(self): - user = User.create(email="foo@bar.com", password="foobar123$") + # def test_password_hashed_on_user_creation(self): + # user = User.create(email="foo@bar.com", password="foobar123$") - assert user.password != "foobar123$" + # assert user.password != "foobar123$" - def test_user_representation(self): - user = User.create(email="foo@bar.com", password="foobar123$") + # def test_user_representation(self): + # user = User.create(email="foo@bar.com", password="foobar123$") - assert repr(user) == f"" + # assert repr(user) == f"" - def test_valid_token_confirms_email(self): - user = User() - user.email = "foo@bar.com" - user.password = "pass" - user.is_email_confirmed = False - user.save() - token = user.generate_confirmation_token() - confirm_status = user.confirm_token(token) + # def test_valid_token_confirms_email(self): + # user = User() + # user.email = "foo@bar.com" + # user.password = "pass" + # user.is_email_confirmed = False + # user.save() + # token = user.generate_confirmation_token() + # confirm_status = user.confirm_token(token) - assert confirm_status is True - assert user.is_email_confirmed + # assert confirm_status is True + # assert user.is_email_confirmed - @freeze_time("Jan 14th, 2020", auto_tick_seconds=200) - def test_expired_token_does_not_confirm_email(self): - user = User.create(email="foo@bar.com", password="foobar123$") - token = user.generate_confirmation_token() - confirm_status = user.confirm_token(token, expiration=120) + # @freeze_time("Jan 14th, 2020", auto_tick_seconds=200) + # def test_expired_token_does_not_confirm_email(self): + # user = User.create(email="foo@bar.com", password="foobar123$") + # token = user.generate_confirmation_token() + # confirm_status = user.confirm_token(token, expiration=120) - assert confirm_status is False - assert not user.is_email_confirmed + # assert confirm_status is False + # assert not user.is_email_confirmed def test_email_should_only_be_confirmed_from_same_email(self): user1 = UserFactory(is_email_confirmed=False) @@ -228,19 +227,19 @@ def test_role_can_have_many_users(self): assert retrived_user1.roles[0] == role assert retrived_user2.roles[0] == role - def test_deleting_role_does_not_remove_user(self): - user = UserFactory() - roles = RoleFactory.create_batch(3) - user.roles = roles - user.save() - roles[0].delete() - retrived_roles = Role.query.all() - retrived_user = User.get_by_id(user.id) + # def test_deleting_role_does_not_remove_user(self): + # user = UserFactory() + # roles = RoleFactory.create_batch(3) + # user.roles = roles + # user.save() + # roles[0].delete() + # retrived_roles = Role.query.all() + # retrived_user = User.get_by_id(user.id) - assert retrived_roles is not None - assert retrived_user is not None - assert len(retrived_roles) == 2 - assert len(retrived_user.roles) == 2 + # assert retrived_roles is not None + # assert retrived_user is not None + # assert len(retrived_roles) == 2 + # assert len(retrived_user.roles) == 2 def test_delete_user_does_not_remove_role(self): users = UserFactory.create_batch(3) @@ -257,21 +256,21 @@ def test_delete_user_does_not_remove_role(self): assert len(retrived_users) == 2 assert len(retrived_role.users) == 2 - def test_role_user_bridge_cascades_on_delete(self): - user1 = UserFactory() - user2 = UserFactory() - roles = RoleFactory.create_batch(3) - user1.roles = roles - user2.roles = roles - user1.save() - user2.save() - user1.delete() - roles[0].delete() - - users_in_bridge = User.query.join(role_user_bridge).join(Role).all() - roles_in_bridge = Role.query.join(role_user_bridge).join(User).all() - - assert roles_in_bridge is not None - assert users_in_bridge is not None - assert len(roles_in_bridge) == 2 - assert len(users_in_bridge) == 1 + # def test_role_user_bridge_cascades_on_delete(self): + # user1 = UserFactory() + # user2 = UserFactory() + # roles = RoleFactory.create_batch(3) + # user1.roles = roles + # user2.roles = roles + # user1.save() + # user2.save() + # user1.delete() + # roles[0].delete() + + # users_in_bridge = User.query.join(role_user_bridge).join(Role).all() + # roles_in_bridge = Role.query.join(role_user_bridge).join(User).all() + + # assert roles_in_bridge is not None + # assert users_in_bridge is not None + # assert len(roles_in_bridge) == 2 + # assert len(users_in_bridge) == 1 diff --git a/src/modules/box__default/auth/upload.py b/pythoncms/modules/box__default/auth/upload.py similarity index 100% rename from src/modules/box__default/auth/upload.py rename to pythoncms/modules/box__default/auth/upload.py diff --git a/src/modules/box__default/auth/view.py b/pythoncms/modules/box__default/auth/view.py similarity index 87% rename from src/modules/box__default/auth/view.py rename to pythoncms/modules/box__default/auth/view.py index 50d1aa7..e10ff26 100644 --- a/src/modules/box__default/auth/view.py +++ b/pythoncms/modules/box__default/auth/view.py @@ -1,8 +1,5 @@ import datetime -import json -import os -from flask import Blueprint from flask import current_app from flask import flash from flask import redirect @@ -13,32 +10,25 @@ from flask_login import login_required from flask_login import login_user from flask_login import logout_user +from shopyo.api.email import send_async_email from shopyo.api.html import notify_danger from shopyo.api.html import notify_success from shopyo.api.html import notify_warning +from shopyo.api.module import ModuleHelp from shopyo.api.security import get_safe_redirect from sqlalchemy import func -from .email import send_async_email from .forms import LoginForm from .forms import RegistrationForm from .models import User -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} -with open(dirpath + "/info.json") as f: - module_info = json.load(f) +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] -auth_blueprint = Blueprint( - "auth", - __name__, - url_prefix=module_info["url_prefix"], - template_folder="templates", -) - -@auth_blueprint.route("/register", methods=["GET", "POST"]) +@module_blueprint.route("/register", methods=["GET", "POST"]) def register(): context = {} @@ -73,7 +63,7 @@ def register(): return render_template("auth/register.html", **context) -@auth_blueprint.route("/confirm/") +@module_blueprint.route("/confirm/") @login_required def confirm(token): @@ -89,7 +79,7 @@ def confirm(token): return redirect(url_for("auth.unconfirmed")) -@auth_blueprint.route("/resend") +@module_blueprint.route("/resend") @login_required def resend(): @@ -105,7 +95,7 @@ def resend(): return redirect(url_for("auth.unconfirmed")) -@auth_blueprint.route("/unconfirmed") +@module_blueprint.route("/unconfirmed") @login_required def unconfirmed(): if current_user.is_email_confirmed: @@ -114,7 +104,7 @@ def unconfirmed(): return render_template("auth/unconfirmed.html") -@auth_blueprint.route("/login", methods=["GET", "POST"]) +@module_blueprint.route("/login", methods=["GET", "POST"]) def login(): context = {} login_form = LoginForm() @@ -139,7 +129,7 @@ def login(): return render_template("auth/login.html", **context) -@auth_blueprint.route("/logout", methods=["GET"]) +@module_blueprint.route("/logout", methods=["GET"]) @login_required def logout(): logout_user() diff --git a/pythoncms/modules/box__default/base/info.json b/pythoncms/modules/box__default/base/info.json new file mode 100644 index 0000000..828da77 --- /dev/null +++ b/pythoncms/modules/box__default/base/info.json @@ -0,0 +1,7 @@ +{ + "display_string": "Base", + "type": "hidden", + "fa-icon": "fas fa-clock", + "url_prefix": "/base", + "module_name": "base" +} diff --git a/src/modules/box__default/base/templates/base/blocks/default_styles.html b/pythoncms/modules/box__default/base/templates/base/blocks/default_styles.html similarity index 100% rename from src/modules/box__default/base/templates/base/blocks/default_styles.html rename to pythoncms/modules/box__default/base/templates/base/blocks/default_styles.html diff --git a/src/modules/box__default/base/templates/base/blocks/flashed_messages.html b/pythoncms/modules/box__default/base/templates/base/blocks/flashed_messages.html similarity index 100% rename from src/modules/box__default/base/templates/base/blocks/flashed_messages.html rename to pythoncms/modules/box__default/base/templates/base/blocks/flashed_messages.html diff --git a/src/modules/box__default/base/templates/base/blocks/footer.html b/pythoncms/modules/box__default/base/templates/base/blocks/footer.html similarity index 100% rename from src/modules/box__default/base/templates/base/blocks/footer.html rename to pythoncms/modules/box__default/base/templates/base/blocks/footer.html diff --git a/src/modules/box__default/base/templates/base/blocks/macros.html b/pythoncms/modules/box__default/base/templates/base/blocks/macros.html similarity index 100% rename from src/modules/box__default/base/templates/base/blocks/macros.html rename to pythoncms/modules/box__default/base/templates/base/blocks/macros.html diff --git a/src/modules/box__default/base/templates/base/blocks/resources.html b/pythoncms/modules/box__default/base/templates/base/blocks/resources.html similarity index 100% rename from src/modules/box__default/base/templates/base/blocks/resources.html rename to pythoncms/modules/box__default/base/templates/base/blocks/resources.html diff --git a/src/modules/box__default/base/templates/base/main_base.html b/pythoncms/modules/box__default/base/templates/base/main_base.html similarity index 100% rename from src/modules/box__default/base/templates/base/main_base.html rename to pythoncms/modules/box__default/base/templates/base/main_base.html diff --git a/src/modules/box__default/base/templates/base/module_base.html b/pythoncms/modules/box__default/base/templates/base/module_base.html similarity index 100% rename from src/modules/box__default/base/templates/base/module_base.html rename to pythoncms/modules/box__default/base/templates/base/module_base.html diff --git a/src/modules/box__default/base/templates/base/nav_base.html b/pythoncms/modules/box__default/base/templates/base/nav_base.html similarity index 100% rename from src/modules/box__default/base/templates/base/nav_base.html rename to pythoncms/modules/box__default/base/templates/base/nav_base.html diff --git a/pythoncms/modules/box__default/base/view.py b/pythoncms/modules/box__default/base/view.py new file mode 100644 index 0000000..66cc9dc --- /dev/null +++ b/pythoncms/modules/box__default/base/view.py @@ -0,0 +1,32 @@ +from shopyo.api.module import ModuleHelp + +# from flask import render_template +# from flask import url_for +# from flask import redirect +# from flask import flash +# from flask import request + +# from shopyo.api.html import notify_success +# from shopyo.api.forms import flash_errors + +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] + + +@module_blueprint.route("/") +def index(): + return mhelp.info["display_string"] + + +# If "dashboard": "/dashboard" is set in info.json +# +# @module_blueprint.route("/dashboard", methods=["GET"]) +# def dashboard(): + +# context = mhelp.context() + +# context.update({ + +# }) +# return mhelp.render('dashboard.html', **context) diff --git a/src/modules/box__default/box_info.json b/pythoncms/modules/box__default/box_info.json similarity index 100% rename from src/modules/box__default/box_info.json rename to pythoncms/modules/box__default/box_info.json diff --git a/pythoncms/modules/box__default/dashboard/info.json b/pythoncms/modules/box__default/dashboard/info.json new file mode 100644 index 0000000..68809d4 --- /dev/null +++ b/pythoncms/modules/box__default/dashboard/info.json @@ -0,0 +1,7 @@ +{ + "display_string": "dashboard", + "type": "hidden", + "fa-icon": "fas fa-clock", + "url_prefix": "/dashboard", + "module_name": "dashboard" +} diff --git a/src/modules/box__default/dashboard/templates/dashboard/index.html b/pythoncms/modules/box__default/dashboard/templates/dashboard/index.html similarity index 100% rename from src/modules/box__default/dashboard/templates/dashboard/index.html rename to pythoncms/modules/box__default/dashboard/templates/dashboard/index.html diff --git a/src/modules/box__default/dashboard/templates/dashboard/nav.html b/pythoncms/modules/box__default/dashboard/templates/dashboard/nav.html similarity index 100% rename from src/modules/box__default/dashboard/templates/dashboard/nav.html rename to pythoncms/modules/box__default/dashboard/templates/dashboard/nav.html diff --git a/pythoncms/modules/box__default/dashboard/tests/test_dashboard.py b/pythoncms/modules/box__default/dashboard/tests/test_dashboard.py new file mode 100644 index 0000000..36ecb96 --- /dev/null +++ b/pythoncms/modules/box__default/dashboard/tests/test_dashboard.py @@ -0,0 +1,46 @@ +""" +This file (test_login.py) contains the functional tests for +the `login` blueprint. + +These tests use GETs and POSTs to different endpoints to check +for the proper behavior of the `login` blueprint. +""" +import pytest +from flask import request +from flask import url_for + + +# class TestDashboardInvalidAccess: +# """ +# Test all dashboard routes for correct user authentication +# """ + +# routes_get = [ +# "/dashboard/", +# ] + +# @pytest.mark.parametrize("route", routes_get) +# def test_redirect_if_not_logged_in_get(self, test_client, route, auth): +# auth.logout() +# response = test_client.get(route, follow_redirects=True) + +# assert response.status_code == 200 +# assert request.path == url_for("auth.login") + +# @pytest.mark.usefixtures("login_unconfirmed_user") +# @pytest.mark.parametrize("route", routes_get) +# def test_redirect_if_email_not_confirmed(self, test_client, route): +# response = test_client.get(route, follow_redirects=True) + +# assert response.status_code == 200 +# assert request.path == url_for("auth.unconfirmed") + + +# @pytest.mark.usefixtures("login_non_admin_user") +# class TestDashboardEndpoints: +# def test_confirmed_user_can_view_dashboard(self, test_client): +# response = test_client.get("/dashboard/", follow_redirects=True) + +# assert response.status_code == 200 +# assert b"Control panel" in response.data +# assert b"Notif test" in response.data diff --git a/src/modules/box__default/dashboard/view.py b/pythoncms/modules/box__default/dashboard/view.py similarity index 88% rename from src/modules/box__default/dashboard/view.py rename to pythoncms/modules/box__default/dashboard/view.py index a90aece..68b6bad 100644 --- a/src/modules/box__default/dashboard/view.py +++ b/pythoncms/modules/box__default/dashboard/view.py @@ -1,27 +1,27 @@ import json import os -from flask import Blueprint from flask import current_app from flask import flash from flask import render_template from flask_login import login_required +from modules.box__default.appadmin.admin import admin_required +from modules.box__default.auth.decorators import check_confirmed from shopyo.api.html import notify_success +from shopyo.api.module import ModuleHelp + +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] -from modules.box__default.auth.decorators import check_confirmed -dashboard_blueprint = Blueprint( - "dashboard", - __name__, - template_folder="templates", - url_prefix="/dashboard", -) all_info = {} @dashboard_blueprint.route("/") @login_required @check_confirmed +@admin_required def index(): context = {} diff --git a/src/modules/box__default/theme/forms.py b/pythoncms/modules/box__default/i18n/forms.py similarity index 100% rename from src/modules/box__default/theme/forms.py rename to pythoncms/modules/box__default/i18n/forms.py diff --git a/pythoncms/modules/box__default/i18n/global.py b/pythoncms/modules/box__default/i18n/global.py new file mode 100644 index 0000000..41536d2 --- /dev/null +++ b/pythoncms/modules/box__default/i18n/global.py @@ -0,0 +1,22 @@ +# global templates variables in here +from .helpers import get_current_lang +from .helpers import get_default_lang +from .helpers import langs + +available_everywhere = { + "get_i18n_langs": langs, + "get_default_lang": get_default_lang, + "get_current_lang": get_current_lang, +} +# global configs in here, defined by profile +# configs = { +# "development": { +# "CONFIG_VAR": "DEVVALUE" +# }, +# "production": { +# "CONFIG_VAR": "PRODVALUE" +# }, +# "testing": { +# "CONFIG_VAR": "TESTVALUE" +# } +# } diff --git a/pythoncms/modules/box__default/i18n/helpers.py b/pythoncms/modules/box__default/i18n/helpers.py new file mode 100644 index 0000000..375b9bb --- /dev/null +++ b/pythoncms/modules/box__default/i18n/helpers.py @@ -0,0 +1,15 @@ +from flask import session + +langs = {"en": "english", "fr": "french"} + + +def lang_keys(): + return (k for k in langs) + + +def get_current_lang(): + return session.get("yo_current_language", "en") + + +def get_default_lang(): + return session.get("yo_default_language", "en") diff --git a/pythoncms/modules/box__default/i18n/info.json b/pythoncms/modules/box__default/i18n/info.json new file mode 100644 index 0000000..c6c7bd7 --- /dev/null +++ b/pythoncms/modules/box__default/i18n/info.json @@ -0,0 +1,12 @@ +{ + "author": { + "mail": "", + "name": "", + "website": "" + }, + "display_string": "I18n", + "fa-icon": "fa fa-store", + "module_name": "i18n", + "type": "show", + "url_prefix": "/i18n" +} diff --git a/pythoncms/modules/box__default/i18n/models.py b/pythoncms/modules/box__default/i18n/models.py new file mode 100644 index 0000000..2485782 --- /dev/null +++ b/pythoncms/modules/box__default/i18n/models.py @@ -0,0 +1,9 @@ +from init import db +from shopyo.api.models import PkModel + + +class LangRecord(PkModel): + __tablename__ = "i18n_records" + strid = db.Column(db.String(1024)) + lang = db.Column(db.String(10)) + string = db.Column(db.Text()) diff --git a/src/modules/resource/templates/resource/blocks/sidebar.html b/pythoncms/modules/box__default/i18n/templates/i18n/blocks/sidebar.html similarity index 100% rename from src/modules/resource/templates/resource/blocks/sidebar.html rename to pythoncms/modules/box__default/i18n/templates/i18n/blocks/sidebar.html diff --git a/pythoncms/modules/box__default/i18n/templates/i18n/dashboard.html b/pythoncms/modules/box__default/i18n/templates/i18n/dashboard.html new file mode 100644 index 0000000..5eebaa0 --- /dev/null +++ b/pythoncms/modules/box__default/i18n/templates/i18n/dashboard.html @@ -0,0 +1,19 @@ +{% extends "base/module_base.html" %} +{% set active_page = info['display_string']+' dashboard' %} +{% block pagehead %} + + +{% endblock %} +{% block sidebar %} +{% include info['module_name']+'/blocks/sidebar.html' %} +{% endblock %} +{% block content %} +
+ +
+
+ +
+
+{% endblock %} diff --git a/pythoncms/modules/box__default/i18n/tests/test_i18n_functional.py b/pythoncms/modules/box__default/i18n/tests/test_i18n_functional.py new file mode 100644 index 0000000..8d45236 --- /dev/null +++ b/pythoncms/modules/box__default/i18n/tests/test_i18n_functional.py @@ -0,0 +1 @@ +# Please add your functional tests to this file. diff --git a/pythoncms/modules/box__default/i18n/tests/test_i18n_models.py b/pythoncms/modules/box__default/i18n/tests/test_i18n_models.py new file mode 100644 index 0000000..c7a836b --- /dev/null +++ b/pythoncms/modules/box__default/i18n/tests/test_i18n_models.py @@ -0,0 +1 @@ +# Please add your models tests to this file. diff --git a/pythoncms/modules/box__default/i18n/view.py b/pythoncms/modules/box__default/i18n/view.py new file mode 100644 index 0000000..8035b6e --- /dev/null +++ b/pythoncms/modules/box__default/i18n/view.py @@ -0,0 +1,46 @@ +from flask import session +from modules.box__default.i18n.helpers import lang_keys +from shopyo.api.module import ModuleHelp + +# from flask import render_template +# from flask import url_for +# from flask import redirect +# from flask import flash +# from flask import request + +# from shopyo.api.html import notify_success +# from shopyo.api.forms import flash_errors + +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] + + +@module_blueprint.route("/") +def index(): + return mhelp.info["display_string"] + + +@module_blueprint.route("/set-lang", methods=["GET"]) +def set_lang(): + set_to_lang = request.args.get("lang", "en") + next_url = request.args.get("next", "/") + + if set_to_lang in lang_keys(): + session["yo_current_lang"] = set_to_lang + session["yo_default_lang"] = set_to_lang + + return redirect(get_safe_url(next_url)) + + +# If "dashboard": "/dashboard" is set in info.json +# +# @module_blueprint.route("/dashboard", methods=["GET"]) +# def dashboard(): + +# context = mhelp.context() + +# context.update({ + +# }) +# return mhelp.render('dashboard.html', **context) diff --git a/src/modules/box__bizhelp/page/forms.py b/pythoncms/modules/box__default/page/forms.py similarity index 82% rename from src/modules/box__bizhelp/page/forms.py rename to pythoncms/modules/box__default/page/forms.py index b2206bf..d8143f0 100644 --- a/src/modules/box__bizhelp/page/forms.py +++ b/pythoncms/modules/box__default/page/forms.py @@ -1,5 +1,7 @@ from flask_wtf import FlaskForm +from modules.box__default.i18n.helpers import langs from shopyo.api.validators import verify_slug +from wtforms import SelectField from wtforms import StringField from wtforms import TextAreaField from wtforms.validators import DataRequired @@ -29,3 +31,4 @@ class PageForm(FlaskForm): [DataRequired()], render_kw={"class": "form-control", "autocomplete": "off"}, ) + lang = SelectField("Language", choices=[(k, v) for k, v in langs.items()]) diff --git a/src/modules/box__bizhelp/page/info.json b/pythoncms/modules/box__default/page/info.json similarity index 100% rename from src/modules/box__bizhelp/page/info.json rename to pythoncms/modules/box__default/page/info.json diff --git a/pythoncms/modules/box__default/page/models.py b/pythoncms/modules/box__default/page/models.py new file mode 100644 index 0000000..a256cff --- /dev/null +++ b/pythoncms/modules/box__default/page/models.py @@ -0,0 +1,73 @@ +from datetime import datetime + +from flask import session +from flask import url_for +from init import db +from modules.box__default.i18n.models import LangRecord +from shopyo.api.models import PkModel + + +class Page(PkModel): + + __tablename__ = "pages" + + created_date = db.Column(db.DateTime, default=datetime.now()) + title = db.Column(db.String(100)) + slug = db.Column(db.String(100)) + + def insert_lang(self, lang, content): + record = LangRecord(strid=self.get_strid(), lang=lang, string=content) + record.save(commit=False) + + def set_lang(self, lang, content, commit=False): + record = LangRecord.query.filter( + LangRecord.strid == self.get_strid(), LangRecord.lang == lang + ).first() + if not record: + record = LangRecord(strid=self.get_strid(), lang=lang, string=content) + record.save(commit=commit) + else: + record.string = content + record.update(commit=commit) + + def get_strid(self): + if self.id is None: + raise Exception("Cannot save page, id none") + return f"page_{self.id}" + + def get_content(self, lang=None): + if not lang: + lang = session.get("yo_current_lang", "en") + Page.query.get(self.id) + record = LangRecord.query.filter( + LangRecord.strid == self.get_strid(), LangRecord.lang == lang + ).first() + if record is None: + return None + + return record.string + + def get_url(self, lang=None): + if self.slug: + if lang: + return url_for("page.view_page", slug=self.slug, lang=lang) + else: + return url_for("page.view_page", slug=self.slug) + else: + return None + + def get_dashboard_url(self, lang=None): + if self.slug: + if lang: + return url_for("page.view_page_dashboard", slug=self.slug, lang=lang) + else: + return url_for("page.view_page_dashboard", slug=self.slug) + else: + return None + + def get_langs(self): + records = LangRecord.query.filter(LangRecord.strid == self.get_strid()).all() + + page_langs = [p.lang for p in records] + + return page_langs diff --git a/src/modules/box__bizhelp/page/templates/page/all_pages.html b/pythoncms/modules/box__default/page/templates/page/all_pages.html similarity index 54% rename from src/modules/box__bizhelp/page/templates/page/all_pages.html rename to pythoncms/modules/box__default/page/templates/page/all_pages.html index 90d8414..c5b7c67 100644 --- a/src/modules/box__bizhelp/page/templates/page/all_pages.html +++ b/pythoncms/modules/box__default/page/templates/page/all_pages.html @@ -1,4 +1,4 @@ -{% extends "base/main_base.html" %} +{% extends "base/module_base.html" %} {% set active_page ='page' %} @@ -14,19 +14,20 @@ {% endblock %} - +{% block sidebar %} +{%include 'page/blocks/sidebar.html'%} +{%endblock%} {% block content %} - +
+
{%for page in pages%} - - - - - - +
+ {% endif %} {%endfor%} +
{% endblock %} diff --git a/src/modules/box__bizhelp/page/templates/page/blocks/sidebar.html b/pythoncms/modules/box__default/page/templates/page/blocks/sidebar.html similarity index 72% rename from src/modules/box__bizhelp/page/templates/page/blocks/sidebar.html rename to pythoncms/modules/box__default/page/templates/page/blocks/sidebar.html index d7aa17e..a7e4ba1 100644 --- a/src/modules/box__bizhelp/page/templates/page/blocks/sidebar.html +++ b/pythoncms/modules/box__default/page/templates/page/blocks/sidebar.html @@ -1,7 +1,7 @@ {{ -sidebar_item('Home', -icon='fa fa-pen', +sidebar_item('New Page', +icon='fa fa-plus', url=url_for('page.dashboard') )}} diff --git a/src/modules/box__bizhelp/page/templates/page/dashboard.html b/pythoncms/modules/box__default/page/templates/page/dashboard.html similarity index 93% rename from src/modules/box__bizhelp/page/templates/page/dashboard.html rename to pythoncms/modules/box__default/page/templates/page/dashboard.html index d4f7bd9..0c9a18c 100644 --- a/src/modules/box__bizhelp/page/templates/page/dashboard.html +++ b/pythoncms/modules/box__default/page/templates/page/dashboard.html @@ -37,12 +37,20 @@

New page

{{ form.slug }} +
+ {{ form.lang.label }}
+
+ {{ form.lang }} +
+
{{ form.content.label }}
{{ form.content }}
+ + diff --git a/src/modules/box__bizhelp/people/__init__.py b/pythoncms/modules/box__default/page/templates/page/dashboard_edit.html similarity index 100% rename from src/modules/box__bizhelp/people/__init__.py rename to pythoncms/modules/box__default/page/templates/page/dashboard_edit.html diff --git a/pythoncms/modules/box__default/page/templates/page/view_page.html b/pythoncms/modules/box__default/page/templates/page/view_page.html new file mode 100644 index 0000000..129bdaf --- /dev/null +++ b/pythoncms/modules/box__default/page/templates/page/view_page.html @@ -0,0 +1,15 @@ + + + + + + {{ page.title }} + + + Demo content page, need to add set lang mechanism by calling `/i18n/set-lang?lang=fr`. +

+ {{ page.title }} +

+ {{ page.get_content() }} + + diff --git a/pythoncms/modules/box__default/page/templates/page/view_page_dashboard.html b/pythoncms/modules/box__default/page/templates/page/view_page_dashboard.html new file mode 100644 index 0000000..1141ef1 --- /dev/null +++ b/pythoncms/modules/box__default/page/templates/page/view_page_dashboard.html @@ -0,0 +1,109 @@ +{% extends "base/module_base.html" %} +{% set active_page ='page' %} +{% block pagehead %} +{{active_page.capitalize()}} + +{% endblock %} +{% block sidebar %} +{%include 'page/blocks/sidebar.html'%} +{%endblock%} +{% block content %} +
+
+
+
+ back +
+ {{ form.title.label }} +
+
+ +
+ {{ form.title }} + +
+ {{ form.slug.label }} +
+
+ +
+ {{ form.slug }} + +
+
+ {{ form.lang.label }}
+
+ {{ form.lang }} +
+
+
+ {{ form.content.label }}
+
+ +
+
+ + + + + +
+
+
+
+ + + +{% endblock %} diff --git a/pythoncms/modules/box__default/page/view.py b/pythoncms/modules/box__default/page/view.py new file mode 100644 index 0000000..15dad34 --- /dev/null +++ b/pythoncms/modules/box__default/page/view.py @@ -0,0 +1,119 @@ +from flask import redirect +from flask import render_template +from flask import request +from flask import url_for +from flask_login import login_required +from init import db +from modules.box__default.i18n.helpers import get_current_lang +from shopyo.api.forms import flash_errors +from shopyo.api.module import ModuleHelp + +from .forms import PageForm +from .models import Page + +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] + + +module_name = mhelp.info["module_name"] + +sidebar = [{"text": "sample", "icon": "fa fa-table", "url": ""}] + +module_settings = {"sidebar": sidebar} + + +@module_blueprint.route(mhelp.info["dashboard"] + "/all") +def index_all(): + context = {} + pages = Page.query.all() + + context.update({"pages": pages}) + return render_template("page/all_pages.html", **context) + + +@module_blueprint.route(mhelp.info["dashboard"] + "/all-pages") +def index(): + context = {} + pages = Page.query.all() + + context.update({"pages": pages}) + return render_template("page/all_pages.html", **context) + + +@module_blueprint.route("dashboard/s/", methods=["GET"]) +def view_page_dashboard(slug): + context = {} + page = Page.query.filter(Page.slug == slug).first() + form = PageForm(obj=page) + + lang_arg = request.args.get("lang", get_current_lang()) + + form.content = page.get_content(lang=lang_arg) + form.lang.data = lang_arg + + context.update({"page": page, "form": form}) + return render_template("page/view_page_dashboard.html", **context) + + +@module_blueprint.route("/s/", methods=["GET"]) +def view_page(slug): + context = {} + page = Page.query.filter(Page.slug == slug).first() + context.update({"page": page}) + return render_template("page/view_page.html", **context) + + +@module_blueprint.route(mhelp.info["dashboard"]) +@login_required +def dashboard(): + context = {} + form = PageForm() + + context.update({"form": form, "module_name": module_name}) + context.update(module_settings) + return render_template("page/dashboard.html", **context) + + +@module_blueprint.route("/check_pagecontent", methods=["GET", "POST"]) +@login_required +def check_pagecontent(): + if request.method == "POST": + form = PageForm() + if not form.validate_on_submit(): + flash_errors(form) + return redirect(url_for(f"{module_name}.dashboard")) + toaddpage = Page( + slug=form.slug.data, + title=form.title.data, + ) + db.session.add(toaddpage) + db.session.flush() + toaddpage.insert_lang(form.lang.data, form.content.data) + toaddpage.save() + return redirect(url_for(f"{module_name}.dashboard")) + + +@module_blueprint.route("/edit_pagecontent", methods=["GET", "POST"]) +@login_required +def edit_pagecontent(): + if request.method == "POST": + form = PageForm() + if not form.validate_on_submit(): + flash_errors(form) + return redirect(url_for(f"{module_name}.dashboard")) + + editpage = db.session.query(Page).get(request.form["page_id"]) + editpage.slug = form.slug.data + editpage.title = form.title.data + editpage.content = form.content.data + + editpage.set_lang(form.lang.data, form.content.data) + db.session.commit() + return redirect( + url_for( + f"{module_name}.view_page_dashboard", + slug=form.slug.data, + lang=form.lang.data, + ) + ) diff --git a/src/modules/box__default/appadmin/__init__.py b/pythoncms/modules/box__default/settings/__init__.py similarity index 100% rename from src/modules/box__default/appadmin/__init__.py rename to pythoncms/modules/box__default/settings/__init__.py diff --git a/src/modules/box__default/settings/helpers.py b/pythoncms/modules/box__default/settings/helpers.py similarity index 100% rename from src/modules/box__default/settings/helpers.py rename to pythoncms/modules/box__default/settings/helpers.py diff --git a/src/modules/box__default/settings/info.json b/pythoncms/modules/box__default/settings/info.json similarity index 58% rename from src/modules/box__default/settings/info.json rename to pythoncms/modules/box__default/settings/info.json index f88bcf2..ce017f6 100644 --- a/src/modules/box__default/settings/info.json +++ b/pythoncms/modules/box__default/settings/info.json @@ -2,5 +2,6 @@ "display_string": "Settings", "type": "show", "fa-icon": "fa fa-cog", - "url_prefix": "/settings" + "url_prefix": "/settings", + "module_name": "settings" } diff --git a/src/modules/box__default/settings/models.py b/pythoncms/modules/box__default/settings/models.py similarity index 100% rename from src/modules/box__default/settings/models.py rename to pythoncms/modules/box__default/settings/models.py diff --git a/src/modules/box__default/settings/templates/settings/edit.html b/pythoncms/modules/box__default/settings/templates/settings/edit.html similarity index 100% rename from src/modules/box__default/settings/templates/settings/edit.html rename to pythoncms/modules/box__default/settings/templates/settings/edit.html diff --git a/src/modules/box__default/settings/templates/settings/index.html b/pythoncms/modules/box__default/settings/templates/settings/index.html similarity index 100% rename from src/modules/box__default/settings/templates/settings/index.html rename to pythoncms/modules/box__default/settings/templates/settings/index.html diff --git a/src/modules/box__default/settings/templates/settings/nav.html b/pythoncms/modules/box__default/settings/templates/settings/nav.html similarity index 100% rename from src/modules/box__default/settings/templates/settings/nav.html rename to pythoncms/modules/box__default/settings/templates/settings/nav.html diff --git a/src/modules/box__default/settings/upload.py b/pythoncms/modules/box__default/settings/upload.py similarity index 100% rename from src/modules/box__default/settings/upload.py rename to pythoncms/modules/box__default/settings/upload.py diff --git a/src/modules/box__default/settings/view.py b/pythoncms/modules/box__default/settings/view.py similarity index 100% rename from src/modules/box__default/settings/view.py rename to pythoncms/modules/box__default/settings/view.py diff --git a/src/modules/resource/forms.py b/pythoncms/modules/box__default/theme/forms.py similarity index 100% rename from src/modules/resource/forms.py rename to pythoncms/modules/box__default/theme/forms.py diff --git a/pythoncms/modules/box__default/theme/global.py b/pythoncms/modules/box__default/theme/global.py new file mode 100644 index 0000000..ecd123a --- /dev/null +++ b/pythoncms/modules/box__default/theme/global.py @@ -0,0 +1,10 @@ +from .helper import * + +available_everywhere = { + "get_active_front_theme": get_active_front_theme, + "get_active_front_theme_version": get_active_front_theme_version, + "get_active_front_theme_styles_url": get_active_front_theme_styles_url, + "get_active_back_theme": get_active_back_theme, + "get_active_back_theme_version": get_active_back_theme_version, + "get_active_back_theme_styles_url": get_active_back_theme_styles_url, +} diff --git a/src/modules/box__default/theme/global.py b/pythoncms/modules/box__default/theme/helper.py similarity index 78% rename from src/modules/box__default/theme/global.py rename to pythoncms/modules/box__default/theme/helper.py index e7a2c1e..7cb5f16 100644 --- a/src/modules/box__default/theme/global.py +++ b/pythoncms/modules/box__default/theme/helper.py @@ -2,7 +2,6 @@ import os from flask import url_for - from init import themes_path from modules.box__default.settings.helpers import get_setting @@ -61,13 +60,3 @@ def get_active_back_theme_styles_url(): active_theme=get_active_back_theme(), v=get_active_back_theme_version(), ) - - -available_everywhere = { - "get_active_front_theme": get_active_front_theme, - "get_active_front_theme_version": get_active_front_theme_version, - "get_active_front_theme_styles_url": get_active_front_theme_styles_url, - "get_active_back_theme": get_active_back_theme, - "get_active_back_theme_version": get_active_back_theme_version, - "get_active_back_theme_styles_url": get_active_back_theme_styles_url, -} diff --git a/src/modules/box__default/theme/info.json b/pythoncms/modules/box__default/theme/info.json similarity index 100% rename from src/modules/box__default/theme/info.json rename to pythoncms/modules/box__default/theme/info.json diff --git a/src/modules/box__default/theme/models.py b/pythoncms/modules/box__default/theme/models.py similarity index 100% rename from src/modules/box__default/theme/models.py rename to pythoncms/modules/box__default/theme/models.py diff --git a/src/modules/box__default/theme/templates/theme/blocks/sidebar.html b/pythoncms/modules/box__default/theme/templates/theme/blocks/sidebar.html similarity index 100% rename from src/modules/box__default/theme/templates/theme/blocks/sidebar.html rename to pythoncms/modules/box__default/theme/templates/theme/blocks/sidebar.html diff --git a/src/modules/box__default/theme/templates/theme/index.html b/pythoncms/modules/box__default/theme/templates/theme/index.html similarity index 100% rename from src/modules/box__default/theme/templates/theme/index.html rename to pythoncms/modules/box__default/theme/templates/theme/index.html diff --git a/src/modules/box__default/theme/view.py b/pythoncms/modules/box__default/theme/view.py similarity index 99% rename from src/modules/box__default/theme/view.py rename to pythoncms/modules/box__default/theme/view.py index ccc8b6c..7158af6 100644 --- a/src/modules/box__default/theme/view.py +++ b/pythoncms/modules/box__default/theme/view.py @@ -7,10 +7,9 @@ from flask import render_template from flask import url_for from flask_login import login_required -from shopyo.api.file import get_folders - from modules.box__default.settings.helpers import get_setting from modules.box__default.settings.helpers import set_setting +from shopyo.api.file import get_folders # from flask import flash # from flask import request diff --git a/src/modules/www/forms.py b/pythoncms/modules/resource/forms.py similarity index 100% rename from src/modules/www/forms.py rename to pythoncms/modules/resource/forms.py diff --git a/pythoncms/modules/resource/info.json b/pythoncms/modules/resource/info.json new file mode 100644 index 0000000..eae1e6d --- /dev/null +++ b/pythoncms/modules/resource/info.json @@ -0,0 +1,12 @@ +{ + "display_string": "Files", + "module_name": "resource", + "type": "hide", + "fa-icon": "fa fa-store", + "url_prefix": "/resource", + "author": { + "name": "", + "website": "", + "mail": "" + } +} diff --git a/src/modules/resource/models.py b/pythoncms/modules/resource/models.py similarity index 100% rename from src/modules/resource/models.py rename to pythoncms/modules/resource/models.py diff --git a/src/modules/www/templates/www/blocks/sidebar.html b/pythoncms/modules/resource/templates/resource/blocks/sidebar.html similarity index 100% rename from src/modules/www/templates/www/blocks/sidebar.html rename to pythoncms/modules/resource/templates/resource/blocks/sidebar.html diff --git a/src/modules/resource/view.py b/pythoncms/modules/resource/view.py similarity index 100% rename from src/modules/resource/view.py rename to pythoncms/modules/resource/view.py diff --git a/src/modules/box__default/settings/__init__.py b/pythoncms/modules/www/forms.py similarity index 100% rename from src/modules/box__default/settings/__init__.py rename to pythoncms/modules/www/forms.py diff --git a/pythoncms/modules/www/global.py b/pythoncms/modules/www/global.py new file mode 100644 index 0000000..4fe60cb --- /dev/null +++ b/pythoncms/modules/www/global.py @@ -0,0 +1,5 @@ +configs = { + "development": {"*********************FUN": "MIAWDEV"}, + "production": {"*********************FUN": "MIAWPROD"}, + "testing": {"*********************FUN": "MIAWTEST"}, +} diff --git a/src/modules/www/info.json b/pythoncms/modules/www/info.json similarity index 100% rename from src/modules/www/info.json rename to pythoncms/modules/www/info.json diff --git a/src/modules/www/models.py b/pythoncms/modules/www/models.py similarity index 100% rename from src/modules/www/models.py rename to pythoncms/modules/www/models.py diff --git a/src/static/themes/front/blogus/sections/footer.html b/pythoncms/modules/www/templates/www/blocks/sidebar.html similarity index 100% rename from src/static/themes/front/blogus/sections/footer.html rename to pythoncms/modules/www/templates/www/blocks/sidebar.html diff --git a/pythoncms/modules/www/templates/www/index.html b/pythoncms/modules/www/templates/www/index.html new file mode 100644 index 0000000..934d428 --- /dev/null +++ b/pythoncms/modules/www/templates/www/index.html @@ -0,0 +1,13 @@ + + + + + + +

Shopyo is now running! Please consult the docs or join the Discord community.

+

Otherwise, go right ahead to the dashboard to get started by logging in with email admin@domain.com and password pass.


+

+ Make sure to run

shopyo initialise
to initialise the db if you are using the default modules! +

+ + diff --git a/src/modules/www/view.py b/pythoncms/modules/www/view.py similarity index 60% rename from src/modules/www/view.py rename to pythoncms/modules/www/view.py index 3813f50..b80cb99 100644 --- a/src/modules/www/view.py +++ b/pythoncms/modules/www/view.py @@ -1,12 +1,8 @@ -import json -import os - -from flask import Blueprint from flask import render_template +from modules.box__default.theme.helper import get_active_front_theme +from shopyo.api.module import ModuleHelp from shopyo.api.templates import yo_render -from modules.box__default.settings.helpers import get_setting - # from flask import url_for # from flask import redirect # from flask import flash @@ -18,22 +14,9 @@ # from shopyo.api.enhance import get_setting # from modules.box__ecommerce.shop.helpers import get_cart_data -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} - -with open(dirpath + "/info.json") as f: - module_info = json.load(f) - - -globals()["{}_blueprint".format(module_info["module_name"])] = Blueprint( - "{}".format(module_info["module_name"]), - __name__, - template_folder="", - url_prefix=module_info["url_prefix"], -) - - -module_blueprint = globals()["{}_blueprint".format(module_info["module_name"])] +mhelp = ModuleHelp(__file__, __name__) +globals()[mhelp.blueprint_str] = mhelp.blueprint +module_blueprint = globals()[mhelp.blueprint_str] @module_blueprint.route("/") @@ -46,7 +29,14 @@ def index(): # return str(module_blueprint.template_folder) - return render_template(get_setting("ACTIVE_FRONT_THEME") + "/index.html") + # return render_template(get_setting("ACTIVE_FRONT_THEME") + "/index.html") + + return render_template( + f"{get_active_front_theme()}/index.html", get_static=get_static + ) + + +from shopyo.api.assets import get_static @module_blueprint.route("/render_demo") diff --git a/src/shopyo_admin.py b/pythoncms/shopyo_admin.py similarity index 100% rename from src/shopyo_admin.py rename to pythoncms/shopyo_admin.py diff --git a/src/static/bootstrap-grid.min.css b/pythoncms/static/bootstrap-grid.min.css similarity index 100% rename from src/static/bootstrap-grid.min.css rename to pythoncms/static/bootstrap-grid.min.css diff --git a/src/static/bootstrap-reboot.min.css b/pythoncms/static/bootstrap-reboot.min.css similarity index 100% rename from src/static/bootstrap-reboot.min.css rename to pythoncms/static/bootstrap-reboot.min.css diff --git a/src/static/bootstrap.bundle.min.js b/pythoncms/static/bootstrap.bundle.min.js similarity index 100% rename from src/static/bootstrap.bundle.min.js rename to pythoncms/static/bootstrap.bundle.min.js diff --git a/src/static/bootstrap.min.css b/pythoncms/static/bootstrap.min.css similarity index 100% rename from src/static/bootstrap.min.css rename to pythoncms/static/bootstrap.min.css diff --git a/src/static/box.svg b/pythoncms/static/box.svg similarity index 100% rename from src/static/box.svg rename to pythoncms/static/box.svg diff --git a/src/static/css/b4vtabs.min.css b/pythoncms/static/css/b4vtabs.min.css similarity index 100% rename from src/static/css/b4vtabs.min.css rename to pythoncms/static/css/b4vtabs.min.css diff --git a/src/static/css/simple_sidebar.css b/pythoncms/static/css/simple_sidebar.css similarity index 100% rename from src/static/css/simple_sidebar.css rename to pythoncms/static/css/simple_sidebar.css diff --git a/src/static/default/default_product.jpg b/pythoncms/static/default/default_product.jpg similarity index 100% rename from src/static/default/default_product.jpg rename to pythoncms/static/default/default_product.jpg diff --git a/src/static/default/default_subcategory.jpg b/pythoncms/static/default/default_subcategory.jpg similarity index 100% rename from src/static/default/default_subcategory.jpg rename to pythoncms/static/default/default_subcategory.jpg diff --git a/src/static/favicon.ico b/pythoncms/static/favicon.ico similarity index 100% rename from src/static/favicon.ico rename to pythoncms/static/favicon.ico diff --git a/src/static/fontawesome/LICENSE.txt b/pythoncms/static/fontawesome/LICENSE.txt similarity index 100% rename from src/static/fontawesome/LICENSE.txt rename to pythoncms/static/fontawesome/LICENSE.txt diff --git a/src/static/fontawesome/css/all.css b/pythoncms/static/fontawesome/css/all.css similarity index 100% rename from src/static/fontawesome/css/all.css rename to pythoncms/static/fontawesome/css/all.css diff --git a/src/static/fontawesome/css/all.min.css b/pythoncms/static/fontawesome/css/all.min.css similarity index 100% rename from src/static/fontawesome/css/all.min.css rename to pythoncms/static/fontawesome/css/all.min.css diff --git a/src/static/fontawesome/css/brands.css b/pythoncms/static/fontawesome/css/brands.css similarity index 100% rename from src/static/fontawesome/css/brands.css rename to pythoncms/static/fontawesome/css/brands.css diff --git a/src/static/fontawesome/css/brands.min.css b/pythoncms/static/fontawesome/css/brands.min.css similarity index 100% rename from src/static/fontawesome/css/brands.min.css rename to pythoncms/static/fontawesome/css/brands.min.css diff --git a/src/static/fontawesome/css/fontawesome.css b/pythoncms/static/fontawesome/css/fontawesome.css similarity index 100% rename from src/static/fontawesome/css/fontawesome.css rename to pythoncms/static/fontawesome/css/fontawesome.css diff --git a/src/static/fontawesome/css/fontawesome.min.css b/pythoncms/static/fontawesome/css/fontawesome.min.css similarity index 100% rename from src/static/fontawesome/css/fontawesome.min.css rename to pythoncms/static/fontawesome/css/fontawesome.min.css diff --git a/src/static/fontawesome/css/regular.css b/pythoncms/static/fontawesome/css/regular.css similarity index 100% rename from src/static/fontawesome/css/regular.css rename to pythoncms/static/fontawesome/css/regular.css diff --git a/src/static/fontawesome/css/regular.min.css b/pythoncms/static/fontawesome/css/regular.min.css similarity index 100% rename from src/static/fontawesome/css/regular.min.css rename to pythoncms/static/fontawesome/css/regular.min.css diff --git a/src/static/fontawesome/css/solid.css b/pythoncms/static/fontawesome/css/solid.css similarity index 100% rename from src/static/fontawesome/css/solid.css rename to pythoncms/static/fontawesome/css/solid.css diff --git a/src/static/fontawesome/css/solid.min.css b/pythoncms/static/fontawesome/css/solid.min.css similarity index 100% rename from src/static/fontawesome/css/solid.min.css rename to pythoncms/static/fontawesome/css/solid.min.css diff --git a/src/static/fontawesome/css/svg-with-js.css b/pythoncms/static/fontawesome/css/svg-with-js.css similarity index 100% rename from src/static/fontawesome/css/svg-with-js.css rename to pythoncms/static/fontawesome/css/svg-with-js.css diff --git a/src/static/fontawesome/css/svg-with-js.min.css b/pythoncms/static/fontawesome/css/svg-with-js.min.css similarity index 100% rename from src/static/fontawesome/css/svg-with-js.min.css rename to pythoncms/static/fontawesome/css/svg-with-js.min.css diff --git a/src/static/fontawesome/css/v4-shims.css b/pythoncms/static/fontawesome/css/v4-shims.css similarity index 100% rename from src/static/fontawesome/css/v4-shims.css rename to pythoncms/static/fontawesome/css/v4-shims.css diff --git a/src/static/fontawesome/css/v4-shims.min.css b/pythoncms/static/fontawesome/css/v4-shims.min.css similarity index 100% rename from src/static/fontawesome/css/v4-shims.min.css rename to pythoncms/static/fontawesome/css/v4-shims.min.css diff --git a/src/static/fontawesome/webfonts/fa-brands-400.eot b/pythoncms/static/fontawesome/webfonts/fa-brands-400.eot similarity index 100% rename from src/static/fontawesome/webfonts/fa-brands-400.eot rename to pythoncms/static/fontawesome/webfonts/fa-brands-400.eot diff --git a/src/static/fontawesome/webfonts/fa-brands-400.svg b/pythoncms/static/fontawesome/webfonts/fa-brands-400.svg similarity index 100% rename from src/static/fontawesome/webfonts/fa-brands-400.svg rename to pythoncms/static/fontawesome/webfonts/fa-brands-400.svg diff --git a/src/static/fontawesome/webfonts/fa-brands-400.ttf b/pythoncms/static/fontawesome/webfonts/fa-brands-400.ttf similarity index 100% rename from src/static/fontawesome/webfonts/fa-brands-400.ttf rename to pythoncms/static/fontawesome/webfonts/fa-brands-400.ttf diff --git a/src/static/fontawesome/webfonts/fa-brands-400.woff b/pythoncms/static/fontawesome/webfonts/fa-brands-400.woff similarity index 100% rename from src/static/fontawesome/webfonts/fa-brands-400.woff rename to pythoncms/static/fontawesome/webfonts/fa-brands-400.woff diff --git a/src/static/fontawesome/webfonts/fa-brands-400.woff2 b/pythoncms/static/fontawesome/webfonts/fa-brands-400.woff2 similarity index 100% rename from src/static/fontawesome/webfonts/fa-brands-400.woff2 rename to pythoncms/static/fontawesome/webfonts/fa-brands-400.woff2 diff --git a/src/static/fontawesome/webfonts/fa-regular-400.eot b/pythoncms/static/fontawesome/webfonts/fa-regular-400.eot similarity index 100% rename from src/static/fontawesome/webfonts/fa-regular-400.eot rename to pythoncms/static/fontawesome/webfonts/fa-regular-400.eot diff --git a/src/static/fontawesome/webfonts/fa-regular-400.svg b/pythoncms/static/fontawesome/webfonts/fa-regular-400.svg similarity index 100% rename from src/static/fontawesome/webfonts/fa-regular-400.svg rename to pythoncms/static/fontawesome/webfonts/fa-regular-400.svg diff --git a/src/static/fontawesome/webfonts/fa-regular-400.ttf b/pythoncms/static/fontawesome/webfonts/fa-regular-400.ttf similarity index 100% rename from src/static/fontawesome/webfonts/fa-regular-400.ttf rename to pythoncms/static/fontawesome/webfonts/fa-regular-400.ttf diff --git a/src/static/fontawesome/webfonts/fa-regular-400.woff b/pythoncms/static/fontawesome/webfonts/fa-regular-400.woff similarity index 100% rename from src/static/fontawesome/webfonts/fa-regular-400.woff rename to pythoncms/static/fontawesome/webfonts/fa-regular-400.woff diff --git a/src/static/fontawesome/webfonts/fa-regular-400.woff2 b/pythoncms/static/fontawesome/webfonts/fa-regular-400.woff2 similarity index 100% rename from src/static/fontawesome/webfonts/fa-regular-400.woff2 rename to pythoncms/static/fontawesome/webfonts/fa-regular-400.woff2 diff --git a/src/static/fontawesome/webfonts/fa-solid-900.eot b/pythoncms/static/fontawesome/webfonts/fa-solid-900.eot similarity index 100% rename from src/static/fontawesome/webfonts/fa-solid-900.eot rename to pythoncms/static/fontawesome/webfonts/fa-solid-900.eot diff --git a/src/static/fontawesome/webfonts/fa-solid-900.svg b/pythoncms/static/fontawesome/webfonts/fa-solid-900.svg similarity index 100% rename from src/static/fontawesome/webfonts/fa-solid-900.svg rename to pythoncms/static/fontawesome/webfonts/fa-solid-900.svg diff --git a/src/static/fontawesome/webfonts/fa-solid-900.ttf b/pythoncms/static/fontawesome/webfonts/fa-solid-900.ttf similarity index 100% rename from src/static/fontawesome/webfonts/fa-solid-900.ttf rename to pythoncms/static/fontawesome/webfonts/fa-solid-900.ttf diff --git a/src/static/fontawesome/webfonts/fa-solid-900.woff b/pythoncms/static/fontawesome/webfonts/fa-solid-900.woff similarity index 100% rename from src/static/fontawesome/webfonts/fa-solid-900.woff rename to pythoncms/static/fontawesome/webfonts/fa-solid-900.woff diff --git a/src/static/fontawesome/webfonts/fa-solid-900.woff2 b/pythoncms/static/fontawesome/webfonts/fa-solid-900.woff2 similarity index 100% rename from src/static/fontawesome/webfonts/fa-solid-900.woff2 rename to pythoncms/static/fontawesome/webfonts/fa-solid-900.woff2 diff --git a/src/static/jquery_3.2.1.min.js b/pythoncms/static/jquery_3.2.1.min.js similarity index 100% rename from src/static/jquery_3.2.1.min.js rename to pythoncms/static/jquery_3.2.1.min.js diff --git a/src/static/js/python.js b/pythoncms/static/js/python.js similarity index 100% rename from src/static/js/python.js rename to pythoncms/static/js/python.js diff --git a/pythoncms/static/modules/box__default/auth/style.css b/pythoncms/static/modules/box__default/auth/style.css new file mode 100644 index 0000000..b5de81c --- /dev/null +++ b/pythoncms/static/modules/box__default/auth/style.css @@ -0,0 +1,7 @@ +/* for styling WTform errors*/ +.form-errors { + list-style-type: none; + padding: 0px; + margin: 0px; + color: red; +} diff --git a/src/static/shopyo.png b/pythoncms/static/shopyo.png similarity index 100% rename from src/static/shopyo.png rename to pythoncms/static/shopyo.png diff --git a/src/static/shopyo.svg b/pythoncms/static/shopyo.svg similarity index 100% rename from src/static/shopyo.svg rename to pythoncms/static/shopyo.svg diff --git a/src/static/themes/back/boogle/info.json b/pythoncms/static/themes/back/boogle/info.json similarity index 100% rename from src/static/themes/back/boogle/info.json rename to pythoncms/static/themes/back/boogle/info.json diff --git a/src/static/themes/back/boogle/styles.css b/pythoncms/static/themes/back/boogle/styles.css similarity index 100% rename from src/static/themes/back/boogle/styles.css rename to pythoncms/static/themes/back/boogle/styles.css diff --git a/src/static/themes/back/mistrello/info.json b/pythoncms/static/themes/back/mistrello/info.json similarity index 100% rename from src/static/themes/back/mistrello/info.json rename to pythoncms/static/themes/back/mistrello/info.json diff --git a/src/static/themes/back/mistrello/styles.css b/pythoncms/static/themes/back/mistrello/styles.css similarity index 100% rename from src/static/themes/back/mistrello/styles.css rename to pythoncms/static/themes/back/mistrello/styles.css diff --git a/src/static/themes/front/blogus/index.html b/pythoncms/static/themes/front/blogus/index.html similarity index 100% rename from src/static/themes/front/blogus/index.html rename to pythoncms/static/themes/front/blogus/index.html diff --git a/src/static/themes/front/blogus/info.json b/pythoncms/static/themes/front/blogus/info.json similarity index 100% rename from src/static/themes/front/blogus/info.json rename to pythoncms/static/themes/front/blogus/info.json diff --git a/src/static/themes/front/blogus/render_demo.html b/pythoncms/static/themes/front/blogus/render_demo.html similarity index 100% rename from src/static/themes/front/blogus/render_demo.html rename to pythoncms/static/themes/front/blogus/render_demo.html diff --git a/src/static/themes/front/blogus/sections/nav.html b/pythoncms/static/themes/front/blogus/sections/footer.html similarity index 100% rename from src/static/themes/front/blogus/sections/nav.html rename to pythoncms/static/themes/front/blogus/sections/footer.html diff --git a/src/static/themes/front/blogus/sections/resources.html b/pythoncms/static/themes/front/blogus/sections/nav.html similarity index 100% rename from src/static/themes/front/blogus/sections/resources.html rename to pythoncms/static/themes/front/blogus/sections/nav.html diff --git a/pythoncms/static/themes/front/blogus/sections/resources.html b/pythoncms/static/themes/front/blogus/sections/resources.html new file mode 100644 index 0000000..e69de29 diff --git a/src/static/themes/front/blogus/styles.css b/pythoncms/static/themes/front/blogus/styles.css similarity index 100% rename from src/static/themes/front/blogus/styles.css rename to pythoncms/static/themes/front/blogus/styles.css diff --git a/src/tests/conftest.py b/pythoncms/tests/conftest.py similarity index 99% rename from src/tests/conftest.py rename to pythoncms/tests/conftest.py index ab2b7c8..498e3ee 100644 --- a/src/tests/conftest.py +++ b/pythoncms/tests/conftest.py @@ -2,9 +2,8 @@ import shutil import pytest -from shopyo.api.file import tryrmtree - from app import create_app +from shopyo.api.file import tryrmtree # from shopyo.app import app as _app diff --git a/pythoncms/tests/test_configs.py b/pythoncms/tests/test_configs.py new file mode 100644 index 0000000..c4fd18c --- /dev/null +++ b/pythoncms/tests/test_configs.py @@ -0,0 +1,57 @@ +""" +test all the different configurations types in +config.py +""" +import pytest + + +class TestAppConfigs: + @pytest.mark.parametrize("app_type", ["development"]) + def test_dev_app_config(self, app): + + config = app.config + + assert "ENV" in config + assert config["ENV"] == "development" + assert "DEBUG" in config + assert config["DEBUG"] is True + assert config["LOGIN_DISABLED"] is not None + assert "SECRET_KEY" in config + assert config["SECRET_KEY"] is not None + assert "SQLALCHEMY_DATABASE_URI" in config + assert config["SQLALCHEMY_DATABASE_URI"] is not None + assert config["MAIL_SERVER"] in ["localhost", "console"] + assert "MAIL_PORT" in config + assert "MAIL_USERNAME" in config + assert "MAIL_PASSWORD" in config + assert "MAIL_DEFAULT_SENDER" in config + + # @pytest.mark.parametrize("app_type", ["production"]) + # def test_prod_app_config(self, app): + # """ + # Test the productions configs. Environment variable + # configs(private configs) are loaded from .test.prod.env just + # to make sure these are loaded correctly + # """ + # config = app.config + + # assert "ENV" in config + # assert config["ENV"] == "production" + # assert "DEBUG" in config + # assert config["DEBUG"] is False + # assert "SECRET_KEY" in config + # assert config["SECRET_KEY"] == "secret" + # assert "EMAIL_CONFIRMATION_DISABLED" in config + # assert config["MAIL_SERVER"] not in ["localhost", "console"] + # assert "MAIL_PORT" in config + # assert "MAIL_USERNAME" in config + # assert config["MAIL_USERNAME"] == "foo@gmail.com" + # assert "MAIL_PASSWORD" in config + # assert config["MAIL_PASSWORD"] == "pass" + # assert "MAIL_DEFAULT_SENDER" in config + # assert config["MAIL_DEFAULT_SENDER"] == "foo@gmail.com" + # assert "SQLALCHEMY_DATABASE_URI" in config + # assert ( + # config["SQLALCHEMY_DATABASE_URI"] + # == "mysql+pymysql://db_username:db_password@db_host/db_name" + # ) diff --git a/pythoncms/tests/test_dunder_main.py b/pythoncms/tests/test_dunder_main.py new file mode 100644 index 0000000..1b9cf29 --- /dev/null +++ b/pythoncms/tests/test_dunder_main.py @@ -0,0 +1,21 @@ +# import os +# import pytest +# from shopyo import __main__ +# def test_no_args(monkeypatch, capfd): +# monkeypatch.setattr("sys.argv", [""]) +# __main__.main() +# captured = capfd.readouterr() +# assert "No arguments supplied" in captured.out +# def test_arg_no_env(monkeypatch, capfd): +# monkeypatch.setattr("sys.argv", ["testok"]) +# __main__.main() +# captured = capfd.readouterr() +# assert "Please use Shopyo in a virtual environment for this command" in captured.out +import subprocess +import sys + + +def test_no_args(capfd): + subprocess.run([sys.executable, "__main__.py"], text=True) + captured = capfd.readouterr() + assert "No arguments supplied" in captured.out diff --git a/pythoncms/tests/test_manage.py b/pythoncms/tests/test_manage.py new file mode 100644 index 0000000..2059957 --- /dev/null +++ b/pythoncms/tests/test_manage.py @@ -0,0 +1,8 @@ +import subprocess +import sys + + +def test_managepy(capfd): + subprocess.run([sys.executable, "manage.py", "testok"], text=True) + captured = capfd.readouterr() + assert "test ok!" in captured.out diff --git a/src/wsgi.py b/pythoncms/wsgi.py.example similarity index 99% rename from src/wsgi.py rename to pythoncms/wsgi.py.example index 8578525..6524926 100644 --- a/src/wsgi.py +++ b/pythoncms/wsgi.py.example @@ -4,6 +4,7 @@ # may need to rename it during the import: # # +import os import sys sys.path.append(os.getcwd()) diff --git a/requirements.txt b/requirements.txt index 90d42cc..0fabe83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1 @@ -click==8.0.4; python_version >= "3.6" -colorama==0.4.4; python_version >= "3.6" and python_full_version >= "3.6.2" and python_full_version < "4.0.0" and (python_version >= "3.6" and python_full_version < "3.0.0" and platform_system == "Windows" or platform_system == "Windows" and python_version >= "3.6" and python_full_version >= "3.5.0") -commonmark==0.9.1; python_full_version >= "3.6.2" and python_full_version < "4.0.0" -importlib-metadata==4.11.3; python_version < "3.8" and python_version >= "3.7" or python_version < "3.8" -pygments==2.11.2; python_full_version >= "3.6.2" and python_full_version < "4.0.0" and python_version >= "3.5" -rich==10.16.2; python_full_version >= "3.6.2" and python_full_version < "4.0.0" -shellingham==1.4.0; python_version >= "3.6" -typer==0.4.0; python_version >= "3.6" -typing-extensions==4.1.1; python_version >= "3.7" and python_version < "3.8" and python_full_version >= "3.6.2" and python_full_version < "4.0.0" -zipp==3.7.0; python_version >= "3.7" and python_version < "3.8" +shopyo==4.8.6 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3c46a08..0000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[darglint] -# https://github.com/terrencepreilly/darglint -strictness = long -docstring_style = google diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..826f901 --- /dev/null +++ b/setup.py @@ -0,0 +1,84 @@ +""" +A setuptools based setup module. +See: +https://packaging.python.org/guides/distributing-packages-using-setuptools/ +https://github.com/pypa/sampleproject + +python setup.py publish to publish + +""" +# Always prefer setuptools over distutils +import os +import sys + +from setuptools import setup + +from pythoncms import __version__ # thanks gunicorn + +# from setuptools import find_packages + +here = os.path.abspath(os.path.dirname(__file__)) + +if sys.argv[-1] == "publish": # requests + os.system("python setup.py sdist") # bdist_wheel + os.system("twine upload dist/* --skip-existing") + sys.exit() + +# Get the long description from the README file +with open(os.path.join(here, "README.md"), encoding="utf-8") as f: + long_description = f.read() +setup( + name="pythoncms", # Required + version=__version__, # Required + description="", # Optional + long_description=long_description, # Optional + long_description_content_type="text/markdown", # Optional (see note above) + url="", # Optional + author="", # Optional + author_email="", # Optional + # Classifiers help users find your project by categorizing it. + # + # For a list of valid classifiers, see https://pypi.org/classifiers/ + classifiers=[ # Optional + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 4 - Beta", + # Indicate who your project is intended for + "Intended Audience :: Developers", + # 'Topic :: Weather', + # Pick your license as you wish + "License :: OSI Approved :: MIT License", + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + # These classifiers are *not* checked by 'pip install'. See instead + # 'python_requires' below. + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + ], + keywords="", # Optional + # You can just specify package directories manually here if your project is + # simple. Or you can use find_packages(). + # + # Alternatively, if you just want to distribute a single Python file, use + # the `py_modules` argument instead as follows, which will expect a file + # called `my_module.py` to exist: + # + # py_modules=["my_module"], + # + # packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required + packages=["pythoncms"], + include_package_data=True, + python_requires=">=3.6", + install_requires=open(os.path.join(here, "requirements.txt"), encoding="utf-8") + .read() + .split("\n"), # Optional + project_urls={ # Optional + "Bug Reports": "", + "Source": "", + }, + entry_points={"console_scripts": ["pythoncms=pythoncms.cli:cli"]}, +) diff --git a/src/app.py b/src/app.py deleted file mode 100644 index 8a1c8b1..0000000 --- a/src/app.py +++ /dev/null @@ -1,182 +0,0 @@ -import importlib -import os -import sys - -import jinja2 -from flask import Flask -from flask import send_from_directory -from flask_admin import Admin -from flask_admin.menu import MenuLink -from flask_login import current_user -from shopyo.api.file import trycopy - -base_path = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, base_path) -from config import app_config -from init import csrf -from init import db -from init import login_manager -from init import ma -from init import mail -from init import migrate -from init import modules_path -from shopyo_admin import DefaultModelView -from shopyo_admin import MyAdminIndexView - - -def create_app(config_name="development"): - - global_entities = {} - app = Flask( - __name__, - instance_path=os.path.join(base_path, "instance"), - instance_relative_config=True, - ) - load_config_from_obj(app, config_name) - load_config_from_instance(app, config_name) - create_config_json() - load_extensions(app) - setup_flask_admin(app) - register_devstatic(app) - load_blueprints(app, global_entities) - setup_theme_paths(app) - inject_global_vars(app, global_entities) - return app - - -def load_config_from_obj(app, config_name): - - try: - configuration = app_config[config_name] - except KeyError as e: - print( - f"[ ] Invalid config name {e}. Available configurations are: " - f"{list(app_config.keys())}\n" - ) - sys.exit(1) - - app.config.from_object(configuration) - - -def load_config_from_instance(app, config_name): - - if config_name != "testing": - # load the instance config, if it exists, when not testing - app.config.from_pyfile("config.py", silent=True) - - # create empty instance folder and empty config if not present - try: - os.makedirs(app.instance_path) - with open(os.path.join(app.instance_path, "config.py"), "a"): - pass - except OSError: - pass - - -def create_config_json(): - if not os.path.exists("config.json"): - trycopy("config_demo.json", "config.json") - - -def load_extensions(app): - migrate.init_app(app, db) - db.init_app(app) - ma.init_app(app) - mail.init_app(app) - login_manager.init_app(app) - csrf.init_app(app) - - -def setup_flask_admin(app): - admin = Admin( - app, - name="My App", - template_mode="bootstrap4", - index_view=MyAdminIndexView(), - ) - # admin.add_view(DefaultModelView(Settings, db.session)) - admin.add_link(MenuLink(name="Logout", category="", url="/auth/logout?next=/admin")) - - -def register_devstatic(app): - @app.route("/devstatic//f/") - def devstatic(boxormodule, filename): - if app.config["DEBUG"]: - module_static = os.path.join(modules_path, boxormodule, "static") - return send_from_directory(module_static, filename=filename) - - -def load_blueprints(app, global_entities): - - for folder in os.listdir(os.path.join(base_path, "modules")): - if folder.startswith("__"): # ignore __pycache__ - continue - - if folder.startswith("box__"): - # boxes - for sub_folder in os.listdir(os.path.join(base_path, "modules", folder)): - if sub_folder.startswith("__"): # ignore __pycache__ - continue - elif sub_folder.endswith(".json"): # box_info.json - continue - try: - sys_mod = importlib.import_module( - f"modules.{folder}.{sub_folder}.view" - ) - app.register_blueprint(getattr(sys_mod, f"{sub_folder}_blueprint")) - except AttributeError: - pass - try: - mod_global = importlib.import_module( - f"modules.{folder}.{sub_folder}.global" - ) - global_entities.update(mod_global.available_everywhere) - except ImportError: - pass - - else: - # apps - try: - mod = importlib.import_module(f"modules.{folder}.view") - app.register_blueprint(getattr(mod, f"{folder}_blueprint")) - except AttributeError: - # print("[ ] Blueprint skipped:", e) - pass - try: - mod_global = importlib.import_module(f"modules.{folder}.global") - global_entities.update(mod_global.available_everywhere) - except ImportError: - # print(f"[ ] {e}") - pass - - -def setup_theme_paths(app): - with app.app_context(): - front_theme_dir = os.path.join( - app.config["BASE_DIR"], "static", "themes", "front" - ) - back_theme_dir = os.path.join( - app.config["BASE_DIR"], "static", "themes", "back" - ) - my_loader = jinja2.ChoiceLoader( - [ - app.jinja_loader, - jinja2.FileSystemLoader([front_theme_dir, back_theme_dir]), - ] - ) - app.jinja_loader = my_loader - - -def inject_global_vars(app, global_entities): - @app.context_processor - def inject_global_vars(): - APP_NAME = "dwdwefw" - - base_context = { - "APP_NAME": APP_NAME, - "len": len, - "current_user": current_user, - } - base_context.update(global_entities) - - return base_context diff --git a/src/modules/box__bizhelp/appointment/info.json b/src/modules/box__bizhelp/appointment/info.json deleted file mode 100644 index 264faba..0000000 --- a/src/modules/box__bizhelp/appointment/info.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "display_string": "Appointments", - "type": "show", - "fa-icon": "fas fa-clock", - "url_prefix": "/appointment", - "author": { - "name":"Abdur-Rahmaan Janhangeer", - "website":"https://www.pythonkitchen.com/about-me/", - "mail":"arj.python@gmail.com" - } -} diff --git a/src/modules/box__bizhelp/appointment/models.py b/src/modules/box__bizhelp/appointment/models.py deleted file mode 100644 index dc15f2a..0000000 --- a/src/modules/box__bizhelp/appointment/models.py +++ /dev/null @@ -1,10 +0,0 @@ -from init import db - - -class Appointments(db.Model): - __tablename__ = "appointments" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(100)) - date = db.Column(db.String(20)) - time = db.Column(db.String(20)) - active = db.Column(db.String(20)) diff --git a/src/modules/box__bizhelp/appointment/templates/appointment/add.html b/src/modules/box__bizhelp/appointment/templates/appointment/add.html deleted file mode 100644 index e516f80..0000000 --- a/src/modules/box__bizhelp/appointment/templates/appointment/add.html +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page = "appointments" %} -{% block pagehead %} -add appointment -{% endblock %} -{% block sidebar %} -{%include 'appointment/blocks/sidebar.html'%} -{%endblock%} -{% block content %} -
-
-
-

Add Appointment

-
- -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- -
- -
- -
- -
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/appointment/templates/appointment/blocks/sidebar.html b/src/modules/box__bizhelp/appointment/templates/appointment/blocks/sidebar.html deleted file mode 100644 index 0ac21cb..0000000 --- a/src/modules/box__bizhelp/appointment/templates/appointment/blocks/sidebar.html +++ /dev/null @@ -1,23 +0,0 @@ -{{ -sidebar_item( -'Home', -icon='fas fa-clock', -url=url_for('appointment.index') -) -}} - -{{ -sidebar_item( -'Add', -icon='fas fa-plus-circle', -url=url_for('appointment.add') -) -}} - -{{ -sidebar_item( -'Search', -icon='fas fa-search', -url=url_for('appointment.lookup') -) -}} diff --git a/src/modules/box__bizhelp/appointment/templates/appointment/edit.html b/src/modules/box__bizhelp/appointment/templates/appointment/edit.html deleted file mode 100644 index 893cad3..0000000 --- a/src/modules/box__bizhelp/appointment/templates/appointment/edit.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page = "appointments" %} -{% block pagehead %} -edit -{% endblock %} -{% block sidebar %} -{%include 'appointment/blocks/sidebar.html'%} -{%endblock%} -{% block content %} -
-
-

Edit Appointment

-
- -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
- - -
- -
- -
-
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/appointment/templates/appointment/index.html b/src/modules/box__bizhelp/appointment/templates/appointment/index.html deleted file mode 100644 index c00f52f..0000000 --- a/src/modules/box__bizhelp/appointment/templates/appointment/index.html +++ /dev/null @@ -1,100 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page = "appointments" %} -{% block pagehead %} -Settings - -{% endblock %} -{% block sidebar %} -{%include 'appointment/blocks/sidebar.html'%} -{%endblock%} -{% block content %} - -
-
-
- - - - - - - - - - - {% for appointment in appointments %} - - - - - - - - {% endfor %} - -
Meeting NameDateTime -
{{ appointment.name }}{{ appointment.date }}{{ appointment.time }} - -
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/appointment/templates/appointment/lookup.html b/src/modules/box__bizhelp/appointment/templates/appointment/lookup.html deleted file mode 100644 index bf37e16..0000000 --- a/src/modules/box__bizhelp/appointment/templates/appointment/lookup.html +++ /dev/null @@ -1,140 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page = "appointments" %} -{% block pagehead %} -add appointment - -{% endblock %} -{% block sidebar %} -{%include 'appointment/blocks/sidebar.html'%} -{%endblock%} -{% block content %} - -
-
-
- -
-
- -
- -
-
-
-

- - - - - - - - - - - - {% for appointment in appointments %} - - - - - - - - {% endfor %} - -
Meeting NameDateTimeActive
{{ appointment.name }}{{ appointment.date }}{{ appointment.time }} - -
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/appointment/view.py b/src/modules/box__bizhelp/appointment/view.py deleted file mode 100644 index 739092e..0000000 --- a/src/modules/box__bizhelp/appointment/view.py +++ /dev/null @@ -1,142 +0,0 @@ -import json -import os - -from flask import Blueprint -from flask import jsonify -from flask import redirect -from flask import render_template -from flask import request -from flask_login import login_required - -from init import db -from init import ma - -from .models import Appointments - -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} - -with open(dirpath + "/info.json") as f: - module_info = json.load(f) - -appointment_blueprint = Blueprint( - "appointment", - __name__, - template_folder="templates", - url_prefix=module_info["url_prefix"], -) - - -class AppointmentSchema(ma.Schema): - class Meta: - # Fields to expose - fields = ("id", "name", "date", "time", "active") - - -appointment_schema = AppointmentSchema() -appointment_schema = AppointmentSchema(many=True) - - -@appointment_blueprint.route("/") -@login_required -def index(): - context = {} - - context["appointments"] = Appointments.query.all() - return render_template("appointment/index.html", **context) - - -@appointment_blueprint.route("/add", methods=["GET", "POST"]) -@login_required -def add(): - context = {} - - if request.method == "POST": - name = request.form["name"] - date = request.form["date"] - active = request.form["active"] - time = request.form["time"] - m = Appointments(name=name, date=date, time=time, active=active) - db.session.add(m) - db.session.commit() - return redirect("/appointment/add") - return render_template("appointment/add.html", **context) - - -@appointment_blueprint.route("/delete/", methods=["GET", "POST"]) -@login_required -def appointment_delete(ids): - Appointments.query.filter(Appointments.id == ids).delete() - db.session.commit() - return redirect("/appointment") - - -@appointment_blueprint.route("/edit/", methods=["GET", "POST"]) -@login_required -def appointment_edit(ids): - context = {} - - a = Appointments.query.get(ids) - context["id"] = a.id - context["name"] = a.name - context["date"] = a.date - context["time"] = a.time - context["active"] = a.active - return render_template("appointment/edit.html", **context) - - -@appointment_blueprint.route("/update", methods=["GET", "POST"]) -@login_required -def appointment_update(): - appointment_name = request.form["appointment_name"] - appointment_date = request.form["appointment_date"] - appointment_time = request.form["appointment_time"] - appointment_id = request.form["appointment_id"] - appointment_active = request.form["appointment_active"] - s = Appointments.query.get(appointment_id) - s.name = appointment_name - s.date = appointment_date - s.time = appointment_time - s.active = appointment_active - db.session.commit() - return redirect("/appointment") - - -@appointment_blueprint.route("/active/", methods=["GET", "POST"]) -@login_required -def active(ids): - s = Appointments.query.get(ids) - s.active = "active" - db.session.commit() - return redirect("/appointment") - - -@appointment_blueprint.route("/inactive/", methods=["GET", "POST"]) -@login_required -def deactive(ids): - s = Appointments.query.get(ids) - s.active = "inactive" - db.session.commit() - return redirect("/appointment") - - -@appointment_blueprint.route("/lookup", methods=["GET", "POST"]) -@login_required -def lookup(): - context = {} - context["appointments"] = Appointments.query.all() - return render_template("appointment/lookup.html", **context) - - -# api -@appointment_blueprint.route("/search/name/", methods=["GET", "POST"]) -@login_required -def search_name(name): - if name == "searchValueIsEmpty": - all_a = Appointments.query.all() - else: - all_a = Appointments.query.filter( - Appointments.name.like("%" + name + "%") - ).all() - result = appointment_schema.dump(all_a) - return jsonify(result) diff --git a/src/modules/box__bizhelp/box_info.json b/src/modules/box__bizhelp/box_info.json deleted file mode 100644 index 93a1f17..0000000 --- a/src/modules/box__bizhelp/box_info.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "display_string": "Bizhelp", - "box_name":"bizhelp", - "author": { - "name":"", - "website":"", - "mail":"" - } - } diff --git a/src/modules/box__bizhelp/contact/forms.py b/src/modules/box__bizhelp/contact/forms.py deleted file mode 100644 index 35f48b1..0000000 --- a/src/modules/box__bizhelp/contact/forms.py +++ /dev/null @@ -1,29 +0,0 @@ -from flask_wtf import FlaskForm -from wtforms import StringField -from wtforms import TextAreaField -from wtforms.fields import EmailField -from wtforms.validators import DataRequired - -# from wtforms.validators import Length - - -class ContactForm(FlaskForm): - name = StringField( - "Name", - [DataRequired()], - render_kw={"class": "form-control", "autocomplete": "off"}, - ) - email = EmailField( - "Email", - [DataRequired()], - render_kw={"class": "form-control", "autocomplete": "off"}, - ) - message = TextAreaField( - "Message", - [DataRequired()], - render_kw={ - "class": "form-control", - "rows": "20", - "autocomplete": "off", - }, - ) diff --git a/src/modules/box__bizhelp/contact/global.py b/src/modules/box__bizhelp/contact/global.py deleted file mode 100644 index f512c5e..0000000 --- a/src/modules/box__bizhelp/contact/global.py +++ /dev/null @@ -1,8 +0,0 @@ -from flask import url_for - - -def get_contact_url(): - return url_for("contact.index") - - -available_everywhere = {"get_contact_url": get_contact_url} diff --git a/src/modules/box__bizhelp/contact/info.json b/src/modules/box__bizhelp/contact/info.json deleted file mode 100644 index c0e0eb4..0000000 --- a/src/modules/box__bizhelp/contact/info.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "display_string": "Contact", - "type": "show", - "fa-icon": "fa fa-envelope", - "url_prefix": "/contact", - "dashboard": "/dashboard", - "author": { - "name":"Abdur-Rahmaan Janhangeer", - "website":"https://www.pythonkitchen.com/about-me/", - "mail":"arj.python@gmail.com" - } -} diff --git a/src/modules/box__bizhelp/contact/models.py b/src/modules/box__bizhelp/contact/models.py deleted file mode 100644 index 7cd6838..0000000 --- a/src/modules/box__bizhelp/contact/models.py +++ /dev/null @@ -1,24 +0,0 @@ -from datetime import datetime - -from init import db - - -class ContactMessage(db.Model): - - __tablename__ = "contact" - id = db.Column(db.Integer, primary_key=True) - created_date = db.Column(db.DateTime, default=datetime.now()) - name = db.Column(db.String(100)) - email = db.Column(db.String(100)) - message = db.Column(db.String(1024)) - - def insert(self): - db.session.add(self) - db.session.commit() - - def update(self): - db.session.commit() - - def delete(self): - db.session.delete(self) - db.session.commit() diff --git a/src/modules/box__bizhelp/contact/templates/contact/blocks/sidebar.html b/src/modules/box__bizhelp/contact/templates/contact/blocks/sidebar.html deleted file mode 100644 index 90d4def..0000000 --- a/src/modules/box__bizhelp/contact/templates/contact/blocks/sidebar.html +++ /dev/null @@ -1,13 +0,0 @@ -{{ -sidebar_item('Home', -icon='fa fa-envelope', -url=url_for('contact.dashboard') -) -}} - -{{ -sidebar_item('Contact Page', -icon='fa fa-globe', -url=url_for('contact.index') -) -}} diff --git a/src/modules/box__bizhelp/contact/templates/contact/contact_form.html b/src/modules/box__bizhelp/contact/templates/contact/contact_form.html deleted file mode 100644 index 7b96202..0000000 --- a/src/modules/box__bizhelp/contact/templates/contact/contact_form.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - {% include get_active_front_theme()+'/sections/resources.html'%} - {% include 'base/blocks/flashed_messages.html'%} - - - {% include get_active_front_theme()+'/sections/nav.html'%} - -
-
- -
- {{ form.name.label }}
-
-
- -
- {{ form.name }} -
-
- -
- {{ form.email.label }}
-
-
- -
- {{ form.email }} -
-
- -
- {{ form.message.label }}
-
-
- -
- {{ form.message }} -
-
-
- - -
-
- - - {% include get_active_front_theme()+'/sections/footer.html'%} - - diff --git a/src/modules/box__bizhelp/contact/templates/contact/dashboard.html b/src/modules/box__bizhelp/contact/templates/contact/dashboard.html deleted file mode 100644 index c892da3..0000000 --- a/src/modules/box__bizhelp/contact/templates/contact/dashboard.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page ='contact dashboard' %} -{% block pagehead %} - - -{% endblock %} -{% block sidebar %} -{%include 'contact/blocks/sidebar.html'%} -{%endblock%} -{% block content %} -
-
-
- - - - - - - - - {%for message in messages.items%} - - - - - - - - - - {%endfor%} - -
NameMailDateInfo
{{message.name}}{{message.email}}{{message.created_date}} - -
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/contact/tests/test_contact.py b/src/modules/box__bizhelp/contact/tests/test_contact.py deleted file mode 100644 index 7818767..0000000 --- a/src/modules/box__bizhelp/contact/tests/test_contact.py +++ /dev/null @@ -1,100 +0,0 @@ -""" -This file (test_contact.py) contains the functional tests for the -`contact` blueprint. - -These tests use GETs and POSTs to different endpoints to check for -the proper behavior of the `contact` blueprint. -""" -from flask import request -from flask import url_for - - -def test_contact_page(test_client): - """ - GIVEN a Flask application configured for testing, - WHEN the /contact page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/contact/") - assert response.status_code == 200 - assert b"Name" in response.data - assert b"Email" in response.data - assert b"Message" in response.data - assert b"Submit" in response.data - - -def test_contact_dashboard(test_client): - """ - GIVEN a Flask application configured for testing, - WHEN the /contact/dashboard page is requested (GET) - THEN check that the response is valid - """ - # Logout and try to access the contact dashboard. It should redirect - response = test_client.get(url_for("auth.logout"), follow_redirects=True) - print(request.path) - assert response.status_code == 200 - assert request.path == url_for("auth.login") - - # check request to contact correctly redirects to login page - response = test_client.get("/contact/dashboard", follow_redirects=True) - assert request.path == url_for("auth.login") - - # Login and try to access the contact dashboard. It should return OK - response = test_client.post( - url_for("auth.login"), - data=dict(email="admin1@domain.com", password="pass"), - follow_redirects=True, - ) - - # check if successfully logged in - assert response.status_code == 200 - - # check response is valid - response = test_client.get(url_for("contact.dashboard")) - assert response.status_code == 200 - assert b"Contact dashboard" in response.data - assert b"Name" in response.data - assert b"Mail" in response.data - assert b"Date" in response.data - assert b"Info" in response.data - assert b"View message" not in response.data - - -def test_contact_validate_msg(test_client): - """ - GIVEN a Flask application configured for testing, - WHEN POST request is made contact validate page - THEN check that the response is valid and that - the new validated message appears on contact dashboard - """ - # GET request should fail for validate message - # Currently test is uncommented since no return statement for - # validate_message for GET - # UNCOMMENT BELOW CODE AFTER FIXING validate_message - # response = test_client.get(url_for("contact.validate_message")) - # assert response.status_code != 200 - - # add a message - response = test_client.post( - url_for("contact.validate_message"), - data=dict(name="User1", email="user1@gmail.com", message="User1 Message"), - follow_redirects=True, - ) - assert response.status_code == 200 - - # check if message was added successfully - response = test_client.get(url_for("contact.dashboard", page=1)) - assert response.status_code == 200 - assert b"Contact dashboard" in response.data - assert b"User1" in response.data - assert b"user1@gmail.com" in response.data - assert b"User1 Message" in response.data - assert b"View message" in response.data - - # change contact page and make sure the message is not there - response = test_client.get(url_for("contact.dashboard", page=2)) - assert response.status_code == 200 - assert b"User1" not in response.data - assert b"user1@gmail.com" not in response.data - assert b"User1 Message" not in response.data - assert b"View message" not in response.data diff --git a/src/modules/box__bizhelp/contact/view.py b/src/modules/box__bizhelp/contact/view.py deleted file mode 100644 index aa107ae..0000000 --- a/src/modules/box__bizhelp/contact/view.py +++ /dev/null @@ -1,59 +0,0 @@ -from flask import Blueprint -from flask import flash -from flask import redirect -from flask import render_template -from flask import request -from flask import url_for -from flask_login import login_required -from shopyo.api.forms import flash_errors -from shopyo.api.html import notify_success - -from .forms import ContactForm -from .models import ContactMessage - -contact_blueprint = Blueprint( - "contact", - __name__, - url_prefix="/contact", - template_folder="templates", -) - - -@contact_blueprint.route("/") -def index(): - context = {} - form = ContactForm() - - context.update({"form": form}) - return render_template("contact/contact_form.html", **context) - - -@contact_blueprint.route("/validate_message", methods=["GET", "POST"]) -@login_required -def validate_message(): - if request.method == "POST": - form = ContactForm() - if not form.validate_on_submit(): - flash_errors(form) - return redirect(url_for("contact.index")) - - name = form.name.data - email = form.email.data - message = form.message.data - - contact_message = ContactMessage(name=name, email=email, message=message) - contact_message.insert() - flash(notify_success("Message submitted!")) - return redirect(url_for("contact.index")) - - -@contact_blueprint.route("/dashboard", methods=["GET"], defaults={"page": 1}) -@contact_blueprint.route("/dashboard/", methods=["GET"]) -@login_required -def dashboard(page): - context = {} - - per_page = 10 - messages = ContactMessage.query.paginate(page, per_page, error_out=False) - context.update({"messages": messages}) - return render_template("contact/dashboard.html", **context) diff --git a/src/modules/box__bizhelp/page/models.py b/src/modules/box__bizhelp/page/models.py deleted file mode 100644 index 64f34a8..0000000 --- a/src/modules/box__bizhelp/page/models.py +++ /dev/null @@ -1,24 +0,0 @@ -from datetime import datetime - -from init import db - - -class Page(db.Model): - - __tablename__ = "pages" - id = db.Column(db.Integer, primary_key=True) - created_date = db.Column(db.DateTime, default=datetime.now()) - title = db.Column(db.String(100)) - slug = db.Column(db.String(100)) - content = db.Column(db.String(1024)) - - def insert(self): - db.session.add(self) - db.session.commit() - - def update(self): - db.session.commit() - - def delete(self): - db.session.delete(self) - db.session.commit() diff --git a/src/modules/box__bizhelp/page/templates/page/view_page.html b/src/modules/box__bizhelp/page/templates/page/view_page.html deleted file mode 100644 index 9601e8b..0000000 --- a/src/modules/box__bizhelp/page/templates/page/view_page.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "base/main_base.html" %} - -{% set active_page ='page' %} - -{% block pagehead %} -{{active_page.capitalize()}} - - -{% endblock %} - -{% block content %} - -
-
-
-

{{page.title}}

-
-
- {{page.content | safe}} -
-
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/page/view.py b/src/modules/box__bizhelp/page/view.py deleted file mode 100644 index 0825133..0000000 --- a/src/modules/box__bizhelp/page/view.py +++ /dev/null @@ -1,81 +0,0 @@ -import json -import os - -from flask import Blueprint -from flask import redirect -from flask import render_template -from flask import request -from flask import url_for -from flask_login import login_required -from shopyo.api.forms import flash_errors - -from .forms import PageForm -from .models import Page - -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} - -with open(dirpath + "/info.json") as f: - module_info = json.load(f) - -globals()["{}_blueprint".format(module_info["module_name"])] = Blueprint( - "{}".format(module_info["module_name"]), - __name__, - template_folder="templates", - url_prefix=module_info["url_prefix"], -) - - -module_blueprint = globals()["{}_blueprint".format(module_info["module_name"])] - -module_name = module_info["module_name"] - -sidebar = [{"text": "sample", "icon": "fa fa-table", "url": ""}] - -module_settings = {"sidebar": sidebar} - - -@module_blueprint.route("/") -def index(): - context = {} - pages = Page.query.all() - - context.update({"pages": pages}) - return render_template("page/all_pages.html", **context) - - -@module_blueprint.route("//") -def view_page(page_id, slug): - context = {} - page = Page.query.get(page_id) - - context.update({"page": page}) - return render_template("page/view_page.html", **context) - - -@module_blueprint.route(module_info["dashboard"]) -@login_required -def dashboard(): - context = {} - form = PageForm() - - context.update({"form": form, "module_name": module_name}) - context.update(module_settings) - return render_template("page/dashboard.html", **context) - - -@module_blueprint.route("/check_pagecontent", methods=["GET", "POST"]) -@login_required -def check_pagecontent(): - if request.method == "POST": - form = PageForm() - if not form.validate_on_submit(): - flash_errors(form) - return redirect(url_for(f"{module_name}.dashboard")) - toaddpage = Page( - slug=form.slug.data, - content=form.content.data, - title=form.title.data, - ) - toaddpage.insert() - return redirect(url_for(f"{module_name}.dashboard")) diff --git a/src/modules/box__bizhelp/people/info.json b/src/modules/box__bizhelp/people/info.json deleted file mode 100644 index 579fba4..0000000 --- a/src/modules/box__bizhelp/people/info.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "display_string": "People", - "type": "show", - "fa-icon": "fa fa-users", - "url_prefix": "/people", - "author": { - "name": "Abdur-Rahmaan Janhangeer", - "website": "https://www.pythonkitchen.com/about-me/", - "mail": "arj.python@gmail.com" - } -} diff --git a/src/modules/box__bizhelp/people/models.py b/src/modules/box__bizhelp/people/models.py deleted file mode 100644 index 59f9425..0000000 --- a/src/modules/box__bizhelp/people/models.py +++ /dev/null @@ -1,20 +0,0 @@ -from init import db - - -class People(db.Model): - __tablename__ = "people" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(100)) - phone = db.Column(db.Integer) - mobile = db.Column(db.Integer) - email = db.Column(db.String(100)) - facebook = db.Column(db.String(128)) - twitter = db.Column(db.String(128)) - linkedin = db.Column(db.String(128)) - age = db.Column(db.Integer) - birthday = db.Column(db.String(100)) - notes = db.Column(db.String(100)) - is_manufacturer = db.Column(db.Boolean) - manufacturer_name = db.Column(db.String(100)) - manufacturer_phone = db.Column(db.Integer) - manufacturer_address = db.Column(db.String(200)) diff --git a/src/modules/box__bizhelp/people/templates/people/add.html b/src/modules/box__bizhelp/people/templates/people/add.html deleted file mode 100644 index 5674959..0000000 --- a/src/modules/box__bizhelp/people/templates/people/add.html +++ /dev/null @@ -1,141 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page ='people' %} -{% block pagehead %} -add people -{% endblock %} -{% block sidebar %} -{%include 'people/blocks/sidebar.html'%} -{%endblock%} -{% block content %} - -
-
-
-
-

Add People

-
-
-
- -
- - {{message}} -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
- -
-
- - -
-
- - -
- - -
-
- -{% endblock %} diff --git a/src/modules/box__bizhelp/people/templates/people/blocks/sidebar.html b/src/modules/box__bizhelp/people/templates/people/blocks/sidebar.html deleted file mode 100644 index c72e755..0000000 --- a/src/modules/box__bizhelp/people/templates/people/blocks/sidebar.html +++ /dev/null @@ -1,24 +0,0 @@ - -{{ -sidebar_item( -'Home', -icon='fas fa-users', -url=url_for('people.index') -) -}} - -{{ -sidebar_item( -'Add', -icon='fas fa-plus-circle', -url=url_for('people.people_add') -) -}} - -{{ -sidebar_item( -'Search', -icon='fas fa-search', -url=url_for('people.lookup') -) -}} diff --git a/src/modules/box__bizhelp/people/templates/people/edit.html b/src/modules/box__bizhelp/people/templates/people/edit.html deleted file mode 100644 index 213852f..0000000 --- a/src/modules/box__bizhelp/people/templates/people/edit.html +++ /dev/null @@ -1,143 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page ='people' %} -{% block pagehead %} -edit -{% endblock %} -{% block sidebar %} -{%include 'people/blocks/sidebar.html'%} -{%endblock%} -{% block content %} - -
-
-
- back -
-
- -
-
-
- -
- -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- - -
-
- -
- -
- -
-
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/people/templates/people/index.html b/src/modules/box__bizhelp/people/templates/people/index.html deleted file mode 100644 index 0315aba..0000000 --- a/src/modules/box__bizhelp/people/templates/people/index.html +++ /dev/null @@ -1,107 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page ='people' %} -{% block pagehead %} -People - -{% endblock %} -{% block sidebar %} -{%include 'people/blocks/sidebar.html'%} -{%endblock%} -{% block content %} -
- -
-
-
- - - - - - - - - - - - {%for person in people%} - - - - - - - - - - - {%endfor%} - -
NamePhoneEmailNote
{{person.name}}{{person.phone}}{{person.email}}{{person.notes}} - - - - - - - -
-
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/people/templates/people/lookup.html b/src/modules/box__bizhelp/people/templates/people/lookup.html deleted file mode 100644 index 83024a5..0000000 --- a/src/modules/box__bizhelp/people/templates/people/lookup.html +++ /dev/null @@ -1,127 +0,0 @@ -{% extends "base/module_base.html" %} -{% set active_page = "people" %} -{% block pagehead %} -add people - -{% endblock %} -{% block sidebar %} -{%include 'people/blocks/sidebar.html'%} -{%endblock%} -{% block content %} - -
-
-
-
-
- -
- -
-
-
-

- - - - - - - - - - - - {% for person in people %} - - - - - - - - {% endfor %} - -
NamePhoneEmailNote
{{ person.name }}{{ person.phone }}{{ person.email }}{{ person.notes }} - - - - - - - -
-
-
-{% endblock %} diff --git a/src/modules/box__bizhelp/people/view.py b/src/modules/box__bizhelp/people/view.py deleted file mode 100644 index f28a6bf..0000000 --- a/src/modules/box__bizhelp/people/view.py +++ /dev/null @@ -1,225 +0,0 @@ -import datetime -import json -import os - -from flask import Blueprint -from flask import jsonify -from flask import redirect -from flask import render_template -from flask import request -from flask_login import login_required - -from init import db -from init import ma - -from .models import People - -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} - -with open(dirpath + "/info.json") as f: - module_info = json.load(f) - -people_blueprint = Blueprint( - "people", - __name__, - template_folder="templates", - url_prefix=module_info["url_prefix"], -) - - -class PeopleSchema(ma.Schema): - class Meta: - # Fields to expose - fields = ( - "id", - "name", - "phone", - "mobile", - "email", - "facebook", - "twitter", - "linkedin", - "age", - "birthday", - "notes", - "is_manufacturer", - "manufacturer_name", - "manufacturer_phone", - "manufacturer_address", - ) - - -people_schema = PeopleSchema() -people_schema = PeopleSchema(many=True) - - -@people_blueprint.route("/") -@login_required -def index(): - context = {} - - context["people"] = People.query.all() - return render_template("people/index.html", **context) - - -@people_blueprint.route("/add", methods=["GET", "POST"]) -@login_required -def people_add(): - context = {} - - if request.method == "POST": - name = request.form["name"] - phone = request.form["phone"] - mobile = request.form["mobile"] - email = request.form["email"] - linkedin = request.form["linkedin"] - facebook = request.form["facebook"] - twitter = request.form["twitter"] - birthday = request.form["birthday"] - notes = request.form["notes"] - is_manufacturer = request.form.get("is_manufacturer", False) - manufacturer_name = request.form.get("manufacturer_name", "") - manufacturer_phone = request.form.get("manufacturer_phone", None) - manufacturer_address = request.form.get("manufacturer_address", "") - - # check if is_manufacturer is true - if is_manufacturer == "on": - is_manufacturer = True - - # calculate age - today_date = datetime.date.today() - date_format = "%Y-%m-%d" - b_day = datetime.datetime.strptime(birthday, date_format) - age = ( - today_date.year - - b_day.year - - ((today_date.month, today_date.day) < (b_day.month, b_day.day)) - ) - - # insert data into DB - person = People( - name=name, - phone=phone, - mobile=mobile, - email=email, - linkedin=linkedin, - facebook=facebook, - twitter=twitter, - age=age, - birthday=birthday, - notes=notes, - is_manufacturer=is_manufacturer, - manufacturer_name=manufacturer_name, - manufacturer_phone=manufacturer_phone, - manufacturer_address=manufacturer_address, - ) - db.session.add(person) - db.session.commit() - return redirect("/people/add") - context["message"] = "" - return render_template("people/add.html", **context) - - -@people_blueprint.route("/delete/", methods=["GET", "POST"]) -@login_required -def people_delete(id): - People.query.filter(People.id == id).delete() - db.session.commit() - return redirect("/people") - - -@people_blueprint.route("/edit/", methods=["GET", "POST"]) -@login_required -def people_edit(id): - context = {} - - a = People.query.get(id) - - context["id"] = a.id - context["name"] = a.name - context["phone"] = a.phone - context["mobile"] = a.mobile - context["email"] = a.email - context["linkedin"] = a.linkedin - context["facebook"] = a.facebook - context["twitter"] = a.twitter - context["age"] = a.age - context["birthday"] = a.birthday - context["notes"] = a.notes - context["is_manufacturer"] = a.is_manufacturer - context["manufacturer_name"] = a.manufacturer_name - context["manufacturer_phone"] = a.manufacturer_phone - context["manufacturer_address"] = a.manufacturer_address - return render_template("people/edit.html", **context) - - -@people_blueprint.route("/update", methods=["GET", "POST"]) -@login_required -def people_update(): - if request.method == "POST": - people_id = request.form["id"] - people_name = request.form["name"] - people_phone = request.form["phone"] - people_mobile = request.form["mobile"] - people_email = request.form["email"] - people_linkedin = request.form["linkedin"] - people_facebook = request.form["facebook"] - people_twitter = request.form["twitter"] - people_birthday = request.form["birthday"] - people_notes = request.form["notes"] - people_is_manufacturer = request.form.get("is_manufacturer", False) - people_manufacturer_name = request.form.get("manufacturer_name", "") - people_manufacturer_phone = request.form.get - ("manufacturer_phone", None) - people_manufacturer_address = request.form.get - ("manufacturer_address", "") - - # check if is_manufacturer is true - if people_is_manufacturer == "on": - people_is_manufacturer = True - - # calculate age - today_date = datetime.datetime.now() - time_format = "%Y-%m-%d" - b_day = datetime.datetime.strptime(people_birthday, time_format) - people_age = str(today_date - b_day) - # retrive record from db with id - s = People.query.get(people_id) - s.name = people_name - s.phone = people_phone - s.mobile = people_mobile - s.email = people_email - s.facebook = people_facebook - s.linkedin = people_linkedin - s.twitter = people_twitter - s.birthday = people_birthday - s.notes = people_notes - s.age = people_age - s.is_manufacturer = people_is_manufacturer - s.manufacturer_name = people_manufacturer_name - s.manufacturer_phone = people_manufacturer_phone - s.manufacturer_address = people_manufacturer_address - db.session.commit() - - return redirect("/people") - - -@people_blueprint.route("/lookup", methods=["GET", "POST"]) -@login_required -def lookup(): - context = {} - context["people"] = People.query.all() - return render_template("people/lookup.html", **context) - - -# api -@people_blueprint.route("/search/name/", methods=["GET", "POST"]) -@login_required -def search_name(name): - if name == "searchValueIsEmpty": - all_a = People.query.all() - else: - all_a = People.query.filter(People.name.like("%" + name + "%")).all() - result = people_schema.dump(all_a) - return jsonify(result) diff --git a/src/modules/box__default/appadmin/tests/test_admin.py b/src/modules/box__default/appadmin/tests/test_admin.py deleted file mode 100644 index 50dd297..0000000 --- a/src/modules/box__default/appadmin/tests/test_admin.py +++ /dev/null @@ -1,366 +0,0 @@ -""" -This file (test_admin.py) contains the functional tests for -the `admin` blueprint. - -These tests use GETs and POSTs to different endpoints to check -for the proper behavior of the `admin` blueprint. -""" -import json -import os - -import pytest -from flask import request -from flask import url_for - -from modules.box__default.auth.models import Role -from modules.box__default.auth.models import User -from modules.box__default.auth.models import role_user_bridge - -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_path = os.path.dirname(dirpath) - -module_info = None - -with open(os.path.join(module_path, "info.json")) as f: - module_info = json.load(f) - - -class TestAdminInvalidAccess: - """ - Test all admin routes for correct user authentication - """ - - routes_get = [ - "/", - "/add", - "/delete/", - "/edit/", - "/roles", - "/roles//delete", - ] - - routes_post = ["/update", "/roles/update", "/roles/add", "/add"] - - @pytest.mark.parametrize("route", routes_get) - def test_redirect_if_not_logged_in_get(self, test_client, route, auth): - auth.logout() - response = test_client.get( - f"{module_info['url_prefix']}{route}", follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.login") - - @pytest.mark.parametrize("route", routes_post) - def test_redirect_if_not_logged_in_post(self, test_client, route, auth): - auth.logout() - response = test_client.post( - f"{module_info['url_prefix']}{route}", follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.login") - - @pytest.mark.usefixtures("login_non_admin_user") - @pytest.mark.parametrize("route", routes_get) - def test_no_admin_access_if_not_admin_get(self, test_client, route): - response = test_client.get( - f"{module_info['url_prefix']}{route}", follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - assert b"You need to be an admin to view this page" in response.data - - @pytest.mark.usefixtures("login_non_admin_user") - @pytest.mark.parametrize("route", routes_post) - def test_no_admin_access_if_not_admin_post(self, test_client, route): - response = test_client.post( - f"{module_info['url_prefix']}{route}", follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - assert b"You need to be an admin to view this page" in response.data - - -@pytest.mark.usefixtures("login_admin_user") -class TestAdminEndpoints: - """ - Test all admin api post and get requests - """ - - def test_admin_user_list_get(self, test_client): - response = test_client.get(f"{module_info['url_prefix']}/") - - assert response.status_code == 200 - assert b"Admin" in response.data - assert b"id" in response.data - assert b"Email" in response.data - assert b"Password" in response.data - assert b"Roles" in response.data - - def test_admin_add_get(self, test_client): - response = test_client.get(f"{module_info['url_prefix']}/add") - - assert response.status_code == 200 - assert b"Email" in response.data - assert b"Password" in response.data - assert b"First Name" in response.data - assert b"Last Name" in response.data - assert b"Admin User" in response.data - - def test_admin_add_unique_user_post(self, test_client): - role1 = Role.create(name="test1-role") - role2 = Role.create(name="test2-role") - data = { - "email": "test@gmail.com", - "password": "pass", - "first_name": "Test", - "last_name": "User", - "is_admin": "", - f"role_{role1.id}": "", - f"role_{role2.id}": "", - } - - test_client.post( - f"{module_info['url_prefix']}/add", - data=data, - follow_redirects=True, - ) - test_user = User.query.filter(User.email == "test@gmail.com").scalar() - - assert test_user is not None - assert test_user.first_name == "Test" - assert test_user.last_name == "User" - assert test_user.is_admin is False - assert test_user.roles is not None - assert len(test_user.roles) == 2 - assert role1.users[0].email == "test@gmail.com" - assert role2.users[0].email == "test@gmail.com" - - def test_admin_add_existing_user_post(self, test_client): - User.create(email="test@gmail.com", password="pass") - data = { - "email": "test@gmail.com", - "password": "pass", - "first_name": "Test", - "last_name": "User", - "is_admin": "", - } - - response = test_client.post( - f"{module_info['url_prefix']}/add", - data=data, - follow_redirects=True, - ) - test_users = User.query.filter(User.email == "test@gmail.com").count() - - assert response.status_code == 200 - assert b"User with same email already exists" in response.data - assert test_users == 1 - - def test_admin_delete_existing_user_get(self, test_client): - user = User(email="test@gmail.com", password="pass") - role1 = Role(name="test1-role") - role2 = Role(name="test2-role") - user.roles = [role1, role2] - user.save() - - response = test_client.get( - f"{module_info['url_prefix']}/delete/{user.id}", - follow_redirects=True, - ) - test_user = User.query.filter(User.email == user.email).scalar() - test_roles = Role.query.count() - user_role = ( - User.query.join(role_user_bridge) - .join(Role) - .filter(User.id == user.id) - .scalar() - ) - - assert response.status_code == 200 - assert test_user is None - assert user_role is None - assert test_roles == 2 - - def test_admin_delete_nonexisting_user_get(self, test_client): - response = test_client.get( - f"{module_info['url_prefix']}/delete/some_id", - follow_redirects=True, - ) - - assert response.status_code == 200 - assert b"Unable to delete. Invalid user id" in response.data - - def test_admin_edit_existing_user_get(self, test_client): - user = User.create(email="test@gmail.com", password="pass") - - response = test_client.get( - f"{module_info['url_prefix']}/edit/{user.id}", - ) - - assert response.status_code == 200 - assert b"test@gmail.com" in response.data - assert b"Edit User" in response.data - - def test_admin_edit_nonexisting_user_get(self, test_client): - response = test_client.get( - f"{module_info['url_prefix']}/edit/some-id", follow_redirects=True - ) - - assert response.status_code == 200 - assert b"Invalid user id" in response.data - assert request.path == f"{module_info['url_prefix']}/" - - def test_admin_update_user_adding_new_roles_to_user(self, test_client): - user = User.create(email="foo@gmail.com", password="pass") - role1 = Role.create(name="test1-role") - role2 = Role.create(name="test2-role") - data = { - "id": str(user.id), - "email": "bar@gmail.com", - "password": "newpass", - "first_name": "Test", - "last_name": "User", - "is_admin": "", - f"role_{role1.id}": "", - f"role_{role2.id}": "", - } - - response = test_client.post( - f"{module_info['url_prefix']}/update", - data=data, - follow_redirects=True, - ) - - assert response.status_code == 200 - assert user.email == "bar@gmail.com" - assert user.check_password("newpass") - assert user.first_name == "Test" - assert user.last_name == "User" - assert len(user.roles) == 2 - assert role1.users[0].email == "bar@gmail.com" - assert role2.users[0].email == "bar@gmail.com" - - def test_admin_update_user_remove_old_roles_from_user(self, test_client): - user = User(email="foo@gmail.com", password="pass", is_admin=True) - user.is_admin = True - role1 = Role(name="test1-role") - role2 = Role(name="test2-role") - user.roles = [role1, role2] - user.save() - data = { - "id": str(user.id), - "email": "bar@gmail.com", - "first_name": "Test", - "last_name": "User", - "password": " ", - "is_admin": None, - } - - response = test_client.post( - f"{module_info['url_prefix']}/update", - data=data, - follow_redirects=True, - ) - - assert response.status_code == 200 - assert user.email == "bar@gmail.com" - assert user.check_password("pass") - assert len(user.roles) == 0 - assert len(role1.users) == 0 - assert len(role2.users) == 0 - - def test_admin_roles_get(self, test_client): - response = test_client.get(f"{module_info['url_prefix']}/roles") - - assert response.status_code == 200 - assert b"Roles" in response.data - - def test_admin_roles_add_nonexisting_role_post(self, test_client): - response = test_client.post( - f"{module_info['url_prefix']}/roles/add", - data=dict(name="new-role"), - follow_redirects=True, - ) - - role = Role.query.filter(Role.name == "new-role").scalar() - role_count = Role.query.count() - - assert response.status_code == 200 - assert role is not None - assert role_count == 1 - - def test_admin_roles_add_existing_role_post(self, test_client): - Role.create(name="new-role") - - response = test_client.post( - f"{module_info['url_prefix']}/roles/add", - data=dict(name="new-role"), - follow_redirects=True, - ) - role_count = Role.query.count() - role = Role.query.filter(Role.name == "new-role").scalar() - - assert response.status_code == 200 - assert b"Role already exists" in response.data - assert role is not None - assert role_count == 1 - - def test_admin_roles_delete_nonexisting_role_get(self, test_client): - response = test_client.get( - f"{module_info['url_prefix']}/roles/some-id/delete", - follow_redirects=True, - ) - - assert response.status_code == 200 - assert request.path == f"{module_info['url_prefix']}/roles" - assert b"Unable to delete. Invalid role id" in response.data - - def test_admin_roles_delete_existing_role_get(self, test_client): - role1 = Role.create(name="new-role1") - role2 = Role.create(name="new-role2") - - response = test_client.get( - f"{module_info['url_prefix']}/roles/{role1.id}/delete", - follow_redirects=True, - ) - roles = Role.query.all() - - assert response.status_code == 200 - assert request.path == f"{module_info['url_prefix']}/roles" - assert b"Role successfully deleted" in response.data - assert roles is not None - assert roles[0].name == role2.name - assert len(roles) == 1 - - def test_admin_roles_update_nonexisting_role_post(self, test_client): - response = test_client.post( - f"{module_info['url_prefix']}/roles/update", - data=dict(role_id="some-id"), - follow_redirects=True, - ) - roles = Role.query.count() - - assert response.status_code == 200 - assert request.path == f"{module_info['url_prefix']}/roles" - assert b"Unable to update. Role does not exist" in response.data - assert roles == 0 - - def test_admin_roles_update_existing_role_post(self, test_client): - new_role = Role.create(name="new-role1") - - response = test_client.post( - f"{module_info['url_prefix']}/roles/update", - data=dict(role_id=new_role.id, role_name="update-role"), - follow_redirects=True, - ) - role = Role.query.scalar() - - assert response.status_code == 200 - assert request.path == f"{module_info['url_prefix']}/roles" - assert b"Role successfully updated" in response.data - assert role is not None - assert role.name == "update-role" diff --git a/src/modules/box__default/auth/email.py b/src/modules/box__default/auth/email.py deleted file mode 100644 index e54587e..0000000 --- a/src/modules/box__default/auth/email.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -This file email.py contains functions for sending -text and html rendered emails asynchronously -""" -from threading import Thread - -from flask import current_app -from flask import render_template -from flask_mailman import EmailMultiAlternatives - - -def _send_email_helper(app, msg): - """ - Helper function used for sending email message - - Args: - app (Flask): The flask app object - msg (flask-mailman email object): any email/messsage object - defined for flask-mailman. Example EmailMessage - """ - with app.app_context(): - if ( - "MAIL_USERNAME" not in current_app.config - or "MAIL_PASSWORD" not in current_app.config - or current_app.config["MAIL_USERNAME"] is None - or current_app.config["MAIL_PASSWORD"] is None - ): - print( - "\nShopyo Error: MAIL_USERNAME, and/or MAIL_PASSWORD not configured\n" - ) - return - - msg.send() - - -def send_async_email(to, subject, template, from_email=None, **kwargs): - """ - Sends email anachronously i.e the function is non blocking. - Assume email template is valid i.e it can be rendered using - flask' render_template function and both .html and .txt - email template files exits - - Args: - to (String): recipient of the email - subject (String): subject of the email - template (String): template file path to be used in email body - from_email (String, optional): sender of the email. If not set - MAIL_DEFAULT_SENDER is used from config. - """ - - if from_email is None: - if ( - "MAIL_DEFAULT_SENDER" not in current_app.config - or current_app.config["MAIL_DEFAULT_SENDER"] is None - ): - print("\nShopyo Error: MAIL_DEFAULT_SENDER not configured\n") - return - - from_email = current_app.config["MAIL_DEFAULT_SENDER"] - - app = current_app._get_current_object() - template_txt = render_template(f"{template}.txt", **kwargs) - template_html = render_template(f"{template}.html", **kwargs) - - msg = EmailMultiAlternatives( - subject=subject, - body=template_txt, - from_email=from_email, - to=[to], - ) - msg.attach_alternative(template_html, "text/html") - - thr = Thread(target=_send_email_helper, args=[app, msg]) - thr.start() - return thr diff --git a/src/modules/box__default/auth/tests/test_auth_functional.py b/src/modules/box__default/auth/tests/test_auth_functional.py deleted file mode 100644 index b8af698..0000000 --- a/src/modules/box__default/auth/tests/test_auth_functional.py +++ /dev/null @@ -1,286 +0,0 @@ -""" -This file (test_auth_functional.py) contains the functional tests for -the `auth` blueprint. - -These tests use GETs and POSTs to different endpoints to check -for the proper behavior of the `auth` module -""" -import json -import os -import threading - -import pytest -from flask import request -from flask import url_for -from flask_login import current_user - -from modules.box__default.auth.models import User - -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_path = os.path.dirname(dirpath) - -module_info = None - -with open(os.path.join(module_path, "info.json")) as f: - module_info = json.load(f) - - -class TestAuthInvalidAccess: - """ - Test all auth routes for correct user authentication - """ - - routes_get = [ - "/confirm/", - "/resend", - "/unconfirmed", - ] - - @pytest.mark.parametrize("route", routes_get) - def test_redirect_if_not_logged_in_get(self, test_client, route, auth): - auth.logout() - response = test_client.get( - f"{module_info['url_prefix']}{route}", follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.login") - - -class TestAuthEndpoints: - """ - Test all auth routes' functionalities - """ - - def test_user_registration_page_renders(self, test_client): - response = test_client.get(f"{module_info['url_prefix']}/register") - - assert response.status_code == 200 - assert b"Email" in response.data - assert b"Password" in response.data - assert b"Confirm Password" in response.data - assert b"Register" in response.data - - def test_user_not_registered_on_invalid_form_submit(self, test_client): - User.create(email="test@gmail.com", password="pass") - data = { - "email": "test@gmail.com", - "password": "password", - "confirm": "password", - } - - response = test_client.post( - f"{module_info['url_prefix']}/register", - data=data, - follow_redirects=True, - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.register") - - def test_user_registration_is_case_insensitive(self, test_client): - User.create(email="foo@bar.com", password="pass") - data = { - "email": "Foo@Bar.com", - "password": "password", - "confirm": "password", - } - - response = test_client.post( - f"{module_info['url_prefix']}/register", - data=data, - follow_redirects=True, - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.register") - - @pytest.mark.parametrize( - "email_config", - [ - ("EMAIL_CONFIRMATION_DISABLED", True), - ], - indirect=True, - ) - def test_user_confirmed_if_email_disabled(self, test_client, email_config): - data = { - "email": "test@gmail.com", - "password": "password", - "confirm": "password", - } - response = test_client.post( - f"{module_info['url_prefix']}/register", - data=data, - follow_redirects=True, - ) - user = User.query.filter(User.email == "test@gmail.com").scalar() - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - assert user.is_email_confirmed is True - - @pytest.mark.parametrize( - "email_config", - [ - ("EMAIL_CONFIRMATION_DISABLED", "remove"), - ("EMAIL_CONFIRMATION_DISABLED", False), - ("EMAIL_CONFIRMATION_DISABLED", None), - ], - indirect=True, - ) - def test_user_is_registered_on_valid_form_submit( - self, test_client, capfd, email_config - ): - data = { - "email": "test@gmail.com", - "password": "password", - "confirm": "password", - } - response = test_client.post( - f"{module_info['url_prefix']}/register", - data=data, - follow_redirects=True, - ) - # Not very happy with this solution. Need a better - # way to wait for the email thread to join with main - # thread before reading the email written to stdout @rehmanis - while threading.activeCount() > 1: - pass - else: - captured = capfd.readouterr() - - user = User.query.filter(User.email == "test@gmail.com").scalar() - - assert response.status_code == 200 - assert request.path == url_for("auth.unconfirmed") - assert b"A confirmation email has been sent via email" in response.data - assert "test@gmail.com" in captured.out - assert "Welcome to Shopyo" in captured.out - assert user is not None - assert user.is_email_confirmed is False - - @pytest.mark.usefixtures("login_non_admin_user") - def test_user_not_confirmed_for_already_confirmed_user(self, test_client): - response = test_client.get( - url_for("auth.confirm", token="sometoken"), follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - assert b"Account already confirmed." in response.data - - @pytest.mark.usefixtures("login_unconfirmed_user") - def test_user_confirmed_on_valid_token(self, test_client): - token = current_user.generate_confirmation_token() - response = test_client.get( - url_for("auth.confirm", token=token), follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - assert b"You have confirmed your account. Thanks!" in response.data - assert current_user.is_email_confirmed is True - - @pytest.mark.usefixtures("login_unconfirmed_user") - def test_no_confirm_sent_for_invalid_token(self, test_client): - token = current_user.generate_confirmation_token() + "extra" - response = test_client.get( - url_for("auth.confirm", token=token), follow_redirects=True - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.unconfirmed") - assert b"The confirmation link is invalid/expired." in response.data - - @pytest.mark.usefixtures("login_non_admin_user") - def test_do_not_allow_email_resend_for_confirmed(self, test_client): - response = test_client.get(url_for("auth.resend"), follow_redirects=True) - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - - @pytest.mark.usefixtures("login_unconfirmed_user") - def test_valid_resend_email_confirmation(self, test_client, capfd): - response = test_client.get(url_for("auth.resend"), follow_redirects=True) - - # Not very happy with this solution. Need a better - # way to wait for the email thread to join with main - # thread before reading the email written to stdout @rehmanis - while threading.activeCount() > 1: - pass - else: - captured = capfd.readouterr() - - assert response.status_code == 200 - assert current_user.email in captured.out - assert "Welcome to Shopyo" in captured.out - assert request.path == url_for("auth.unconfirmed") - assert b"A new confirmation email has been sent" in response.data - - @pytest.mark.usefixtures("login_non_admin_user") - def test_confirmed_user_is_redirected_to_dashboard(self, test_client): - response = test_client.get(url_for("auth.unconfirmed"), follow_redirects=True) - - assert response.status_code == 200 - assert request.path == url_for("dashboard.index") - - @pytest.mark.usefixtures("login_unconfirmed_user") - def test_unconfirmed_page_renders_correctly(self, test_client): - response = test_client.get(url_for("auth.unconfirmed")) - - assert response.status_code == 200 - assert request.path == url_for("auth.unconfirmed") - assert b"You have not confirmed your account" in response.data - assert b"Email confirmation link was sent to" in response.data - assert current_user.email.encode() in response.data - - def test_login_for_dashboard_renders(self, test_client): - response = test_client.get(url_for("auth.login")) - - assert response.status_code == 200 - assert b"Login" in response.data - assert b"submit" in response.data - - def test_invalid_dashboard_login(self, test_client): - response = test_client.post( - url_for("auth.login"), - data=dict(email="admin1@domain.com", password="wrongpass"), - follow_redirects=True, - ) - - assert response.status_code == 200 - assert request.path == url_for("auth.login") - assert b"please check your user id and password" in response.data - - def test_valid_dashboard_login(self, test_client, non_admin_user): - response = test_client.post( - url_for("auth.login"), - data=dict(email=non_admin_user.email, password="pass"), - follow_redirects=True, - ) - - assert response.status_code == 200 - assert current_user.email == non_admin_user.email - assert request.path == url_for("dashboard.index") - - def test_valid_dashboard_login_is_case_insensitive(self, test_client): - User.create(email="foo@bar.com", password="pass") - data = {"email": "Foo@Bar.com", "password": "pass"} - response = test_client.post( - url_for("auth.login"), - data=data, - follow_redirects=True, - ) - - assert response.status_code == 200 - assert current_user.email.lower() == data["email"].lower() - assert request.path == url_for("auth.unconfirmed") - - @pytest.mark.usefixtures("login_non_admin_user") - def test_current_user_logout(self, test_client): - response = test_client.get(url_for("auth.logout"), follow_redirects=True) - - assert response.status_code == 200 - assert request.path == url_for("auth.login") - assert b"Successfully logged out" in response.data - assert current_user.is_authenticated is False diff --git a/src/modules/box__default/auth/tests/test_email.py b/src/modules/box__default/auth/tests/test_email.py deleted file mode 100644 index b21b2ba..0000000 --- a/src/modules/box__default/auth/tests/test_email.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -This file (test_email.py) contains the unit tests for -functions defined in email.py which is used for sending -user email confirmation -""" -import pytest -from flask_mailman import EmailMessage - -from modules.box__default.auth.email import _send_email_helper -from modules.box__default.auth.email import send_async_email -from modules.box__default.auth.models import User - - -@pytest.mark.parametrize( - "email_config", - [("MAIL_DEFAULT_SENDER", "remove"), ("MAIL_DEFAULT_SENDER", None)], - indirect=True, -) -def test_send_email_with_no_default_sender(capfd, email_config): - user = User.create(email="test@gmail.com", password="pass") - token = "sometoken" - template = "auth/emails/activate_user" - subject = "Please confirm your email" - context = {"token": token, "user": user} - send_async_email(user.email, subject, template, **context) - captured = capfd.readouterr() - - assert "Shopyo Error: MAIL_DEFAULT_SENDER not configured" in captured.out - - -@pytest.mark.parametrize( - "email_config", - [ - ("MAIL_USERNAME", "remove"), - ("MAIL_PASSWORD", "remove"), - ("MAIL_USERNAME", None), - ("MAIL_PASSWORD", None), - ], - indirect=True, -) -def test_send_email_with_no_username_or_password_set(capfd, email_config): - user = User.create(email="test@gmail.com", password="pass") - token = "sometoken" - template = "auth/emails/activate_user" - subject = "Please confirm your email" - context = {"token": token, "user": user} - thread = send_async_email(user.email, subject, template, **context) - thread.join() - captured = capfd.readouterr() - - assert ( - "Shopyo Error: MAIL_USERNAME, and/or MAIL_PASSWORD not configured" - in captured.out - ) - - -def test_send_email_using_template_on_valid_credentials(capfd): - user = User.create(email="to@gmail.com", password="pass") - token = "sometoken" - template = "auth/emails/activate_user" - subject = "Please confirm your email" - from_email = "from@gmail.com" - context = {"token": token, "user": user} - thread = send_async_email( - user.email, subject, template, from_email=from_email, **context - ) - thread.join() - captured = capfd.readouterr() - - assert "Please confirm your email" in captured.out - assert "sometoken" in captured.out - assert "to@gmail.com" in captured.out - assert "from@gmail.com" in captured.out - assert "Welcome to Shopyo" in captured.out - assert "To confirm your account please click on" in captured.out - assert "The Shopyo Team" in captured.out - - -def test_send_using_helper_function(test_client, flask_app, capfd): - msg = EmailMessage( - subject="subject of email", - body="body of email", - to=["to@test.com"], - from_email="from@test.com", - ) - _send_email_helper(flask_app, msg) - captured = capfd.readouterr() - - assert "to@test.com" in captured.out - assert "from@test.com" in captured.out - assert "subject of email" in captured.out - assert "body of email" in captured.out diff --git a/src/modules/box__default/base/info.json b/src/modules/box__default/base/info.json deleted file mode 100644 index e978a81..0000000 --- a/src/modules/box__default/base/info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "display_string": "Base", - "type": "hidden", - "fa-icon": "fas fa-clock", - "url_prefix": "/base" -} diff --git a/src/modules/box__default/base/view.py b/src/modules/box__default/base/view.py deleted file mode 100644 index 2f896ee..0000000 --- a/src/modules/box__default/base/view.py +++ /dev/null @@ -1,17 +0,0 @@ -import json -import os - -from flask import Blueprint - -dirpath = os.path.dirname(os.path.abspath(__file__)) -module_info = {} - -with open(dirpath + "/info.json") as f: - module_info = json.load(f) - -base_blueprint = Blueprint( - "base", - __name__, - url_prefix=module_info["url_prefix"], - template_folder="templates", -) diff --git a/src/modules/box__default/dashboard/tests/test_dashboard.py b/src/modules/box__default/dashboard/tests/test_dashboard.py deleted file mode 100644 index 1096048..0000000 --- a/src/modules/box__default/dashboard/tests/test_dashboard.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -This file (test_login.py) contains the functional tests for -the `login` blueprint. - -These tests use GETs and POSTs to different endpoints to check -for the proper behavior of the `login` blueprint. -""" -import pytest -from flask import request -from flask import url_for - - -class TestDashboardInvalidAccess: - """ - Test all dashboard routes for correct user authentication - """ - - routes_get = [ - "/dashboard/", - ] - - @pytest.mark.parametrize("route", routes_get) - def test_redirect_if_not_logged_in_get(self, test_client, route, auth): - auth.logout() - response = test_client.get(route, follow_redirects=True) - - assert response.status_code == 200 - assert request.path == url_for("auth.login") - - @pytest.mark.usefixtures("login_unconfirmed_user") - @pytest.mark.parametrize("route", routes_get) - def test_redirect_if_email_not_confirmed(self, test_client, route): - response = test_client.get(route, follow_redirects=True) - - assert response.status_code == 200 - assert request.path == url_for("auth.unconfirmed") - - -@pytest.mark.usefixtures("login_non_admin_user") -class TestDashboardEndpoints: - def test_confirmed_user_can_view_dashboard(self, test_client): - response = test_client.get("/dashboard/", follow_redirects=True) - - assert response.status_code == 200 - assert b"Control panel" in response.data - assert b"Notif test" in response.data diff --git a/src/modules/resource/info.json b/src/modules/resource/info.json deleted file mode 100644 index f80a6ac..0000000 --- a/src/modules/resource/info.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "display_string": "Files", - "module_name":"resource", - "type": "hide", - "fa-icon": "fa fa-store", - "url_prefix": "/resource", - "author": { - "name":"", - "website":"", - "mail":"" - } -} diff --git a/src/modules/www/templates/www/index.html b/src/modules/www/templates/www/index.html deleted file mode 100644 index b42ae9b..0000000 --- a/src/modules/www/templates/www/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -

WWW Index

-

Fruit {{ fruit }}

diff --git a/src/tests/test_configs.py b/src/tests/test_configs.py deleted file mode 100644 index 622bc7a..0000000 --- a/src/tests/test_configs.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -test all the different configurations types in -config.py -""" -import pytest - - -class TestAppConfigs: - @pytest.mark.parametrize("app_type", ["development"]) - def test_dev_app_config(self, app): - - config = app.config - - assert "ENV" in config - assert config["ENV"] == "development" - assert "DEBUG" in config - assert config["DEBUG"] is True - assert config["LOGIN_DISABLED"] is not None - assert "SECRET_KEY" in config - assert config["SECRET_KEY"] is not None - assert "SQLALCHEMY_DATABASE_URI" in config - assert config["SQLALCHEMY_DATABASE_URI"] is not None - assert config["MAIL_SERVER"] in ["localhost", "console"] - assert "MAIL_PORT" in config - assert "MAIL_USERNAME" in config - assert "MAIL_PASSWORD" in config - assert "MAIL_DEFAULT_SENDER" in config - - @pytest.mark.parametrize("app_type", ["production"]) - def test_prod_app_config(self, app): - """ - Test the productions configs. Environment variable - configs(private configs) are loaded from .test.prod.env just - to make sure these are loaded correctly - """ - config = app.config - - assert "ENV" in config - assert config["ENV"] == "production" - assert "DEBUG" in config - assert config["DEBUG"] is False - assert "SECRET_KEY" in config - assert config["SECRET_KEY"] == "secret" - assert "EMAIL_CONFIRMATION_DISABLED" in config - assert config["MAIL_SERVER"] not in ["localhost", "console"] - assert "MAIL_PORT" in config - assert "MAIL_USERNAME" in config - assert config["MAIL_USERNAME"] == "foo@gmail.com" - assert "MAIL_PASSWORD" in config - assert config["MAIL_PASSWORD"] == "pass" - assert "MAIL_DEFAULT_SENDER" in config - assert config["MAIL_DEFAULT_SENDER"] == "foo@gmail.com" - assert "SQLALCHEMY_DATABASE_URI" in config - assert ( - config["SQLALCHEMY_DATABASE_URI"] - == "mysql+pymysql://db_username:db_password@db_host/db_name" - ) diff --git a/tests/test_example/test_hello.py b/tests/test_example/test_hello.py deleted file mode 100644 index 901f2e7..0000000 --- a/tests/test_example/test_hello.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Tests for hello function.""" -import pytest - - -def test_pythoncms(): - assert 1 == 1 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..81da807 --- /dev/null +++ b/tox.ini @@ -0,0 +1,14 @@ +[tox] +envlist = + py39 + py38 + py37 + py36 +skip_missing_interpreters=true + +[testenv] +changedir = pythoncms +deps = + -rrequirements.txt + -rdev_requirements.txt +commands = python -m pytest {posargs} From 36181472978ca1e42e35a61a5d372b4a744fb19c Mon Sep 17 00:00:00 2001 From: Abdur-Rahmaan Janhangeer Date: Tue, 31 Jan 2023 23:15:59 +0400 Subject: [PATCH 2/4] feat: Add new themes --- .../migrations/versions/9c6ee690afb6_.py | 36 + pythoncms/modules/box__default/i18n/info.json | 2 +- pythoncms/modules/box__default/i18n/view.py | 5 +- pythoncms/modules/box__default/page/view.py | 5 +- .../modules/box__default/theme/global.py | 2 +- .../theme/{helper.py => helpers.py} | 0 pythoncms/modules/contact/forms.py | 29 + pythoncms/modules/contact/global.py | 8 + pythoncms/modules/contact/info.json | 12 + pythoncms/modules/contact/models.py | 24 + .../templates/contact/blocks/sidebar.html | 13 + .../templates/contact/contact_form.html | 52 + .../contact/templates/contact/dashboard.html | 60 + .../modules/contact/tests/test_contact.py | 100 + pythoncms/modules/contact/view.py | 58 + pythoncms/modules/www/view.py | 2 +- .../static/themes/front/blogus/index.html | 409 +- .../static/themes/front/blogus/page.html | 15 + .../static/themes/front/editorial/LICENSE.txt | 63 + .../static/themes/front/editorial/README.txt | 30 + .../assets/css/fontawesome-all.min.css | 101 + .../front/editorial/assets/css/main.css | 2273 ++++++++++ .../editorial/assets/js/breakpoints.min.js | 2 + .../front/editorial/assets/js/browser.min.js | 2 + .../front/editorial/assets/js/jquery.min.js | 2 + .../themes/front/editorial/assets/js/main.js | 262 ++ .../themes/front/editorial/assets/js/util.js | 587 +++ .../editorial/assets/sass/base/_page.scss | 48 + .../editorial/assets/sass/base/_reset.scss | 76 + .../assets/sass/base/_typography.scss | 187 + .../assets/sass/components/_actions.scss | 63 + .../assets/sass/components/_box.scss | 26 + .../assets/sass/components/_button.scss | 85 + .../assets/sass/components/_contact.scss | 47 + .../assets/sass/components/_features.scss | 156 + .../assets/sass/components/_form.scss | 179 + .../assets/sass/components/_icon.scss | 33 + .../assets/sass/components/_icons.scss | 30 + .../assets/sass/components/_image.scss | 74 + .../assets/sass/components/_list.scss | 56 + .../assets/sass/components/_mini-posts.scss | 31 + .../assets/sass/components/_pagination.scss | 70 + .../assets/sass/components/_posts.scss | 179 + .../assets/sass/components/_row.scss | 31 + .../assets/sass/components/_section.scss | 39 + .../assets/sass/components/_table.scss | 81 + .../editorial/assets/sass/layout/_banner.scss | 75 + .../editorial/assets/sass/layout/_footer.scss | 18 + .../editorial/assets/sass/layout/_header.scss | 51 + .../editorial/assets/sass/layout/_main.scss | 58 + .../editorial/assets/sass/layout/_menu.scss | 98 + .../assets/sass/layout/_sidebar.scss | 223 + .../assets/sass/layout/_wrapper.scss | 13 + .../assets/sass/libs/_breakpoints.scss | 223 + .../assets/sass/libs/_functions.scss | 90 + .../assets/sass/libs/_html-grid.scss | 149 + .../editorial/assets/sass/libs/_mixins.scss | 78 + .../editorial/assets/sass/libs/_vars.scss | 44 + .../editorial/assets/sass/libs/_vendor.scss | 376 ++ .../front/editorial/assets/sass/main.scss | 62 + .../static/themes/front/editorial/base.html | 27 + .../themes/front/editorial/elements.html | 543 +++ .../themes/front/editorial/generic.html | 172 + .../themes/front/editorial/images/pic01.jpg | Bin 0 -> 20660 bytes .../themes/front/editorial/images/pic02.jpg | Bin 0 -> 20986 bytes .../themes/front/editorial/images/pic03.jpg | Bin 0 -> 21127 bytes .../themes/front/editorial/images/pic04.jpg | Bin 0 -> 21412 bytes .../themes/front/editorial/images/pic05.jpg | Bin 0 -> 21497 bytes .../themes/front/editorial/images/pic06.jpg | Bin 0 -> 21564 bytes .../themes/front/editorial/images/pic07.jpg | Bin 0 -> 10854 bytes .../themes/front/editorial/images/pic08.jpg | Bin 0 -> 10934 bytes .../themes/front/editorial/images/pic09.jpg | Bin 0 -> 10350 bytes .../themes/front/editorial/images/pic10.jpg | Bin 0 -> 70746 bytes .../themes/front/editorial/images/pic11.jpg | Bin 0 -> 99292 bytes .../static/themes/front/editorial/index.html | 144 + .../static/themes/front/editorial/info.json | 4 + .../static/themes/front/editorial/page.html | 43 + .../themes/front/editorial/render_demo.html | 3 + .../front/editorial/sections/footer.html | 0 .../themes/front/editorial/sections/nav.html | 0 .../front/editorial/sections/resources.html | 0 .../front/editorial/sections/sidebar.html | 91 + .../static/themes/front/editorial/styles.css | 41 + .../themes/front/hyperspace/LICENSE.txt | 63 + .../static/themes/front/hyperspace/README.txt | 33 + .../assets/css/fontawesome-all.min.css | 101 + .../hyperspace/assets/css/images/intro.svg | 24 + .../front/hyperspace/assets/css/main.css | 3909 +++++++++++++++++ .../front/hyperspace/assets/css/noscript.css | 43 + .../hyperspace/assets/js/breakpoints.min.js | 2 + .../front/hyperspace/assets/js/browser.min.js | 2 + .../front/hyperspace/assets/js/jquery.min.js | 2 + .../assets/js/jquery.scrollex.min.js | 2 + .../assets/js/jquery.scrolly.min.js | 2 + .../themes/front/hyperspace/assets/js/main.js | 190 + .../themes/front/hyperspace/assets/js/util.js | 587 +++ .../hyperspace/assets/sass/base/_page.scss | 47 + .../hyperspace/assets/sass/base/_reset.scss | 76 + .../assets/sass/base/_typography.scss | 200 + .../assets/sass/components/_actions.scss | 101 + .../assets/sass/components/_box.scss | 26 + .../assets/sass/components/_button.scss | 106 + .../assets/sass/components/_contact.scss | 21 + .../assets/sass/components/_features.scss | 98 + .../assets/sass/components/_form.scss | 237 + .../assets/sass/components/_icon.scss | 73 + .../assets/sass/components/_icons.scss | 30 + .../assets/sass/components/_image.scss | 60 + .../assets/sass/components/_list.scss | 56 + .../assets/sass/components/_menu.scss | 36 + .../assets/sass/components/_row.scss | 31 + .../assets/sass/components/_section.scss | 41 + .../assets/sass/components/_split.scss | 91 + .../assets/sass/components/_spotlights.scss | 130 + .../assets/sass/components/_table.scss | 81 + .../assets/sass/components/_wrapper.scss | 139 + .../assets/sass/layout/_footer.scss | 38 + .../assets/sass/layout/_header.scss | 92 + .../hyperspace/assets/sass/layout/_intro.scss | 33 + .../assets/sass/layout/_sidebar.scss | 185 + .../assets/sass/layout/_wrapper.scss | 30 + .../assets/sass/libs/_breakpoints.scss | 223 + .../assets/sass/libs/_functions.scss | 90 + .../assets/sass/libs/_html-grid.scss | 149 + .../hyperspace/assets/sass/libs/_mixins.scss | 78 + .../hyperspace/assets/sass/libs/_vars.scss | 49 + .../hyperspace/assets/sass/libs/_vendor.scss | 376 ++ .../front/hyperspace/assets/sass/main.scss | 58 + .../hyperspace/assets/sass/noscript.scss | 57 + .../static/themes/front/hyperspace/base.html | 38 + .../themes/front/hyperspace/elements.html | 363 ++ .../themes/front/hyperspace/generic.html | 50 + .../themes/front/hyperspace/images/pic01.jpg | Bin 0 -> 6953 bytes .../themes/front/hyperspace/images/pic02.jpg | Bin 0 -> 5767 bytes .../themes/front/hyperspace/images/pic03.jpg | Bin 0 -> 6828 bytes .../themes/front/hyperspace/images/pic04.jpg | Bin 0 -> 12171 bytes .../themes/front/hyperspace/images/pic05.jpg | Bin 0 -> 2527 bytes .../themes/front/hyperspace/images/pic06.jpg | Bin 0 -> 2798 bytes .../static/themes/front/hyperspace/index.html | 177 + .../static/themes/front/hyperspace/info.json | 4 + .../static/themes/front/hyperspace/page.html | 17 + .../themes/front/hyperspace/render_demo.html | 3 + .../front/hyperspace/sections/footer.html | 0 .../themes/front/hyperspace/sections/nav.html | 0 .../front/hyperspace/sections/resources.html | 0 .../static/themes/front/hyperspace/styles.css | 41 + 146 files changed, 17052 insertions(+), 10 deletions(-) create mode 100644 pythoncms/migrations/versions/9c6ee690afb6_.py rename pythoncms/modules/box__default/theme/{helper.py => helpers.py} (100%) create mode 100644 pythoncms/modules/contact/forms.py create mode 100644 pythoncms/modules/contact/global.py create mode 100644 pythoncms/modules/contact/info.json create mode 100644 pythoncms/modules/contact/models.py create mode 100644 pythoncms/modules/contact/templates/contact/blocks/sidebar.html create mode 100644 pythoncms/modules/contact/templates/contact/contact_form.html create mode 100644 pythoncms/modules/contact/templates/contact/dashboard.html create mode 100644 pythoncms/modules/contact/tests/test_contact.py create mode 100644 pythoncms/modules/contact/view.py create mode 100644 pythoncms/static/themes/front/blogus/page.html create mode 100644 pythoncms/static/themes/front/editorial/LICENSE.txt create mode 100644 pythoncms/static/themes/front/editorial/README.txt create mode 100644 pythoncms/static/themes/front/editorial/assets/css/fontawesome-all.min.css create mode 100644 pythoncms/static/themes/front/editorial/assets/css/main.css create mode 100644 pythoncms/static/themes/front/editorial/assets/js/breakpoints.min.js create mode 100644 pythoncms/static/themes/front/editorial/assets/js/browser.min.js create mode 100644 pythoncms/static/themes/front/editorial/assets/js/jquery.min.js create mode 100644 pythoncms/static/themes/front/editorial/assets/js/main.js create mode 100644 pythoncms/static/themes/front/editorial/assets/js/util.js create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/base/_page.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/base/_reset.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/base/_typography.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_actions.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_box.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_button.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_contact.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_features.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_form.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_icon.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_icons.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_image.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_list.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_mini-posts.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_pagination.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_posts.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_row.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_section.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/components/_table.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_banner.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_footer.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_header.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_main.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_menu.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_sidebar.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/layout/_wrapper.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/libs/_breakpoints.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/libs/_functions.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/libs/_html-grid.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/libs/_mixins.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/libs/_vars.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/libs/_vendor.scss create mode 100644 pythoncms/static/themes/front/editorial/assets/sass/main.scss create mode 100644 pythoncms/static/themes/front/editorial/base.html create mode 100644 pythoncms/static/themes/front/editorial/elements.html create mode 100644 pythoncms/static/themes/front/editorial/generic.html create mode 100644 pythoncms/static/themes/front/editorial/images/pic01.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic02.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic03.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic04.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic05.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic06.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic07.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic08.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic09.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic10.jpg create mode 100644 pythoncms/static/themes/front/editorial/images/pic11.jpg create mode 100644 pythoncms/static/themes/front/editorial/index.html create mode 100644 pythoncms/static/themes/front/editorial/info.json create mode 100644 pythoncms/static/themes/front/editorial/page.html create mode 100644 pythoncms/static/themes/front/editorial/render_demo.html create mode 100644 pythoncms/static/themes/front/editorial/sections/footer.html create mode 100644 pythoncms/static/themes/front/editorial/sections/nav.html create mode 100644 pythoncms/static/themes/front/editorial/sections/resources.html create mode 100644 pythoncms/static/themes/front/editorial/sections/sidebar.html create mode 100644 pythoncms/static/themes/front/editorial/styles.css create mode 100644 pythoncms/static/themes/front/hyperspace/LICENSE.txt create mode 100644 pythoncms/static/themes/front/hyperspace/README.txt create mode 100644 pythoncms/static/themes/front/hyperspace/assets/css/fontawesome-all.min.css create mode 100644 pythoncms/static/themes/front/hyperspace/assets/css/images/intro.svg create mode 100644 pythoncms/static/themes/front/hyperspace/assets/css/main.css create mode 100644 pythoncms/static/themes/front/hyperspace/assets/css/noscript.css create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/breakpoints.min.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/browser.min.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/jquery.min.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/jquery.scrollex.min.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/jquery.scrolly.min.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/main.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/js/util.js create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/base/_page.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/base/_reset.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/base/_typography.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_actions.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_box.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_button.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_contact.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_features.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_form.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_icon.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_icons.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_image.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_list.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_menu.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_row.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_section.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_split.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_spotlights.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_table.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/components/_wrapper.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/layout/_footer.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/layout/_header.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/layout/_intro.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/layout/_sidebar.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/layout/_wrapper.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/libs/_breakpoints.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/libs/_functions.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/libs/_html-grid.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/libs/_mixins.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vars.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vendor.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/main.scss create mode 100644 pythoncms/static/themes/front/hyperspace/assets/sass/noscript.scss create mode 100644 pythoncms/static/themes/front/hyperspace/base.html create mode 100644 pythoncms/static/themes/front/hyperspace/elements.html create mode 100644 pythoncms/static/themes/front/hyperspace/generic.html create mode 100644 pythoncms/static/themes/front/hyperspace/images/pic01.jpg create mode 100644 pythoncms/static/themes/front/hyperspace/images/pic02.jpg create mode 100644 pythoncms/static/themes/front/hyperspace/images/pic03.jpg create mode 100644 pythoncms/static/themes/front/hyperspace/images/pic04.jpg create mode 100644 pythoncms/static/themes/front/hyperspace/images/pic05.jpg create mode 100644 pythoncms/static/themes/front/hyperspace/images/pic06.jpg create mode 100644 pythoncms/static/themes/front/hyperspace/index.html create mode 100644 pythoncms/static/themes/front/hyperspace/info.json create mode 100644 pythoncms/static/themes/front/hyperspace/page.html create mode 100644 pythoncms/static/themes/front/hyperspace/render_demo.html create mode 100644 pythoncms/static/themes/front/hyperspace/sections/footer.html create mode 100644 pythoncms/static/themes/front/hyperspace/sections/nav.html create mode 100644 pythoncms/static/themes/front/hyperspace/sections/resources.html create mode 100644 pythoncms/static/themes/front/hyperspace/styles.css diff --git a/pythoncms/migrations/versions/9c6ee690afb6_.py b/pythoncms/migrations/versions/9c6ee690afb6_.py new file mode 100644 index 0000000..4b4f8ea --- /dev/null +++ b/pythoncms/migrations/versions/9c6ee690afb6_.py @@ -0,0 +1,36 @@ +"""empty message + +Revision ID: 9c6ee690afb6 +Revises: cb42bf1aaf17 +Create Date: 2023-01-31 23:13:25.916695 + +""" +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "9c6ee690afb6" +down_revision = "cb42bf1aaf17" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "contact", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("created_date", sa.DateTime(), nullable=True), + sa.Column("name", sa.String(length=100), nullable=True), + sa.Column("email", sa.String(length=100), nullable=True), + sa.Column("message", sa.String(length=1024), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("contact") + # ### end Alembic commands ### diff --git a/pythoncms/modules/box__default/i18n/info.json b/pythoncms/modules/box__default/i18n/info.json index c6c7bd7..daf808f 100644 --- a/pythoncms/modules/box__default/i18n/info.json +++ b/pythoncms/modules/box__default/i18n/info.json @@ -7,6 +7,6 @@ "display_string": "I18n", "fa-icon": "fa fa-store", "module_name": "i18n", - "type": "show", + "type": "hide", "url_prefix": "/i18n" } diff --git a/pythoncms/modules/box__default/i18n/view.py b/pythoncms/modules/box__default/i18n/view.py index 8035b6e..2d38256 100644 --- a/pythoncms/modules/box__default/i18n/view.py +++ b/pythoncms/modules/box__default/i18n/view.py @@ -1,6 +1,9 @@ +from flask import redirect +from flask import request from flask import session from modules.box__default.i18n.helpers import lang_keys from shopyo.api.module import ModuleHelp +from shopyo.api.security import get_safe_redirect # from flask import render_template # from flask import url_for @@ -30,7 +33,7 @@ def set_lang(): session["yo_current_lang"] = set_to_lang session["yo_default_lang"] = set_to_lang - return redirect(get_safe_url(next_url)) + return redirect(get_safe_redirect(next_url)) # If "dashboard": "/dashboard" is set in info.json diff --git a/pythoncms/modules/box__default/page/view.py b/pythoncms/modules/box__default/page/view.py index 15dad34..d0c9989 100644 --- a/pythoncms/modules/box__default/page/view.py +++ b/pythoncms/modules/box__default/page/view.py @@ -5,6 +5,7 @@ from flask_login import login_required from init import db from modules.box__default.i18n.helpers import get_current_lang +from modules.box__default.theme.helpers import get_active_front_theme from shopyo.api.forms import flash_errors from shopyo.api.module import ModuleHelp @@ -61,7 +62,9 @@ def view_page(slug): context = {} page = Page.query.filter(Page.slug == slug).first() context.update({"page": page}) - return render_template("page/view_page.html", **context) + + return render_template(f"{get_active_front_theme()}/page.html", **context) + # return render_template("page/view_page.html", **context) @module_blueprint.route(mhelp.info["dashboard"]) diff --git a/pythoncms/modules/box__default/theme/global.py b/pythoncms/modules/box__default/theme/global.py index ecd123a..eed0fe5 100644 --- a/pythoncms/modules/box__default/theme/global.py +++ b/pythoncms/modules/box__default/theme/global.py @@ -1,4 +1,4 @@ -from .helper import * +from .helpers import * available_everywhere = { "get_active_front_theme": get_active_front_theme, diff --git a/pythoncms/modules/box__default/theme/helper.py b/pythoncms/modules/box__default/theme/helpers.py similarity index 100% rename from pythoncms/modules/box__default/theme/helper.py rename to pythoncms/modules/box__default/theme/helpers.py diff --git a/pythoncms/modules/contact/forms.py b/pythoncms/modules/contact/forms.py new file mode 100644 index 0000000..d894a60 --- /dev/null +++ b/pythoncms/modules/contact/forms.py @@ -0,0 +1,29 @@ +from flask_wtf import FlaskForm +from wtforms import EmailField +from wtforms import StringField +from wtforms import TextAreaField +from wtforms.validators import DataRequired + +# from wtforms.validators import Length + + +class ContactForm(FlaskForm): + name = StringField( + "Name", + [DataRequired()], + render_kw={"class": "form-control", "autocomplete": "off"}, + ) + email = EmailField( + "Email", + [DataRequired()], + render_kw={"class": "form-control", "autocomplete": "off"}, + ) + message = TextAreaField( + "Message", + [DataRequired()], + render_kw={ + "class": "form-control", + "rows": "20", + "autocomplete": "off", + }, + ) diff --git a/pythoncms/modules/contact/global.py b/pythoncms/modules/contact/global.py new file mode 100644 index 0000000..f512c5e --- /dev/null +++ b/pythoncms/modules/contact/global.py @@ -0,0 +1,8 @@ +from flask import url_for + + +def get_contact_url(): + return url_for("contact.index") + + +available_everywhere = {"get_contact_url": get_contact_url} diff --git a/pythoncms/modules/contact/info.json b/pythoncms/modules/contact/info.json new file mode 100644 index 0000000..c0e0eb4 --- /dev/null +++ b/pythoncms/modules/contact/info.json @@ -0,0 +1,12 @@ +{ + "display_string": "Contact", + "type": "show", + "fa-icon": "fa fa-envelope", + "url_prefix": "/contact", + "dashboard": "/dashboard", + "author": { + "name":"Abdur-Rahmaan Janhangeer", + "website":"https://www.pythonkitchen.com/about-me/", + "mail":"arj.python@gmail.com" + } +} diff --git a/pythoncms/modules/contact/models.py b/pythoncms/modules/contact/models.py new file mode 100644 index 0000000..7cd6838 --- /dev/null +++ b/pythoncms/modules/contact/models.py @@ -0,0 +1,24 @@ +from datetime import datetime + +from init import db + + +class ContactMessage(db.Model): + + __tablename__ = "contact" + id = db.Column(db.Integer, primary_key=True) + created_date = db.Column(db.DateTime, default=datetime.now()) + name = db.Column(db.String(100)) + email = db.Column(db.String(100)) + message = db.Column(db.String(1024)) + + def insert(self): + db.session.add(self) + db.session.commit() + + def update(self): + db.session.commit() + + def delete(self): + db.session.delete(self) + db.session.commit() diff --git a/pythoncms/modules/contact/templates/contact/blocks/sidebar.html b/pythoncms/modules/contact/templates/contact/blocks/sidebar.html new file mode 100644 index 0000000..90d4def --- /dev/null +++ b/pythoncms/modules/contact/templates/contact/blocks/sidebar.html @@ -0,0 +1,13 @@ +{{ +sidebar_item('Home', +icon='fa fa-envelope', +url=url_for('contact.dashboard') +) +}} + +{{ +sidebar_item('Contact Page', +icon='fa fa-globe', +url=url_for('contact.index') +) +}} diff --git a/pythoncms/modules/contact/templates/contact/contact_form.html b/pythoncms/modules/contact/templates/contact/contact_form.html new file mode 100644 index 0000000..7b96202 --- /dev/null +++ b/pythoncms/modules/contact/templates/contact/contact_form.html @@ -0,0 +1,52 @@ + + + + + {% include get_active_front_theme()+'/sections/resources.html'%} + {% include 'base/blocks/flashed_messages.html'%} + + + {% include get_active_front_theme()+'/sections/nav.html'%} + +
+
+ +
+ {{ form.name.label }}
+
+
+ +
+ {{ form.name }} +
+
+ +
+ {{ form.email.label }}
+
+
+ +
+ {{ form.email }} +
+
+ +
+ {{ form.message.label }}
+
+
+ +
+ {{ form.message }} +
+
+
+ + +
+
+ + + {% include get_active_front_theme()+'/sections/footer.html'%} + + diff --git a/pythoncms/modules/contact/templates/contact/dashboard.html b/pythoncms/modules/contact/templates/contact/dashboard.html new file mode 100644 index 0000000..c892da3 --- /dev/null +++ b/pythoncms/modules/contact/templates/contact/dashboard.html @@ -0,0 +1,60 @@ +{% extends "base/module_base.html" %} +{% set active_page ='contact dashboard' %} +{% block pagehead %} + + +{% endblock %} +{% block sidebar %} +{%include 'contact/blocks/sidebar.html'%} +{%endblock%} +{% block content %} +
+
+
+ + + + + + + + + {%for message in messages.items%} + + + + + + + + + + {%endfor%} + +
NameMailDateInfo
{{message.name}}{{message.email}}{{message.created_date}} + +
+
+
+{% endblock %} diff --git a/pythoncms/modules/contact/tests/test_contact.py b/pythoncms/modules/contact/tests/test_contact.py new file mode 100644 index 0000000..7818767 --- /dev/null +++ b/pythoncms/modules/contact/tests/test_contact.py @@ -0,0 +1,100 @@ +""" +This file (test_contact.py) contains the functional tests for the +`contact` blueprint. + +These tests use GETs and POSTs to different endpoints to check for +the proper behavior of the `contact` blueprint. +""" +from flask import request +from flask import url_for + + +def test_contact_page(test_client): + """ + GIVEN a Flask application configured for testing, + WHEN the /contact page is requested (GET) + THEN check that the response is valid + """ + response = test_client.get("/contact/") + assert response.status_code == 200 + assert b"Name" in response.data + assert b"Email" in response.data + assert b"Message" in response.data + assert b"Submit" in response.data + + +def test_contact_dashboard(test_client): + """ + GIVEN a Flask application configured for testing, + WHEN the /contact/dashboard page is requested (GET) + THEN check that the response is valid + """ + # Logout and try to access the contact dashboard. It should redirect + response = test_client.get(url_for("auth.logout"), follow_redirects=True) + print(request.path) + assert response.status_code == 200 + assert request.path == url_for("auth.login") + + # check request to contact correctly redirects to login page + response = test_client.get("/contact/dashboard", follow_redirects=True) + assert request.path == url_for("auth.login") + + # Login and try to access the contact dashboard. It should return OK + response = test_client.post( + url_for("auth.login"), + data=dict(email="admin1@domain.com", password="pass"), + follow_redirects=True, + ) + + # check if successfully logged in + assert response.status_code == 200 + + # check response is valid + response = test_client.get(url_for("contact.dashboard")) + assert response.status_code == 200 + assert b"Contact dashboard" in response.data + assert b"Name" in response.data + assert b"Mail" in response.data + assert b"Date" in response.data + assert b"Info" in response.data + assert b"View message" not in response.data + + +def test_contact_validate_msg(test_client): + """ + GIVEN a Flask application configured for testing, + WHEN POST request is made contact validate page + THEN check that the response is valid and that + the new validated message appears on contact dashboard + """ + # GET request should fail for validate message + # Currently test is uncommented since no return statement for + # validate_message for GET + # UNCOMMENT BELOW CODE AFTER FIXING validate_message + # response = test_client.get(url_for("contact.validate_message")) + # assert response.status_code != 200 + + # add a message + response = test_client.post( + url_for("contact.validate_message"), + data=dict(name="User1", email="user1@gmail.com", message="User1 Message"), + follow_redirects=True, + ) + assert response.status_code == 200 + + # check if message was added successfully + response = test_client.get(url_for("contact.dashboard", page=1)) + assert response.status_code == 200 + assert b"Contact dashboard" in response.data + assert b"User1" in response.data + assert b"user1@gmail.com" in response.data + assert b"User1 Message" in response.data + assert b"View message" in response.data + + # change contact page and make sure the message is not there + response = test_client.get(url_for("contact.dashboard", page=2)) + assert response.status_code == 200 + assert b"User1" not in response.data + assert b"user1@gmail.com" not in response.data + assert b"User1 Message" not in response.data + assert b"View message" not in response.data diff --git a/pythoncms/modules/contact/view.py b/pythoncms/modules/contact/view.py new file mode 100644 index 0000000..978aa47 --- /dev/null +++ b/pythoncms/modules/contact/view.py @@ -0,0 +1,58 @@ +from flask import Blueprint +from flask import flash +from flask import redirect +from flask import render_template +from flask import request +from flask import url_for +from flask_login import login_required +from shopyo.api.html import notify_success + +from .forms import ContactForm +from .models import ContactMessage + +contact_blueprint = Blueprint( + "contact", + __name__, + url_prefix="/contact", + template_folder="templates", +) + + +@contact_blueprint.route("/") +def index(): + context = {} + form = ContactForm() + + context.update({"form": form}) + return render_template("contact/contact_form.html", **context) + + +@contact_blueprint.route("/validate_message", methods=["GET", "POST"]) +@login_required +def validate_message(): + if request.method == "POST": + form = ContactForm() + if not form.validate_on_submit(): + flash_errors(form) + return redirect(url_for("contact.index")) + + name = form.name.data + email = form.email.data + message = form.message.data + + contact_message = ContactMessage(name=name, email=email, message=message) + contact_message.insert() + flash(notify_success("Message submitted!")) + return redirect(url_for("contact.index")) + + +@contact_blueprint.route("/dashboard", methods=["GET"], defaults={"page": 1}) +@contact_blueprint.route("/dashboard/", methods=["GET"]) +@login_required +def dashboard(page): + context = {} + + per_page = 10 + messages = ContactMessage.query.paginate(page, per_page, error_out=False) + context.update({"messages": messages}) + return render_template("contact/dashboard.html", **context) diff --git a/pythoncms/modules/www/view.py b/pythoncms/modules/www/view.py index b80cb99..109530d 100644 --- a/pythoncms/modules/www/view.py +++ b/pythoncms/modules/www/view.py @@ -1,5 +1,5 @@ from flask import render_template -from modules.box__default.theme.helper import get_active_front_theme +from modules.box__default.theme.helpers import get_active_front_theme from shopyo.api.module import ModuleHelp from shopyo.api.templates import yo_render diff --git a/pythoncms/static/themes/front/blogus/index.html b/pythoncms/static/themes/front/blogus/index.html index 1371eb3..812efcd 100644 --- a/pythoncms/static/themes/front/blogus/index.html +++ b/pythoncms/static/themes/front/blogus/index.html @@ -1,10 +1,409 @@ - - + + + - + + + Bootstrap demo + + + -

Shopyo is now running! Please consult the docs or join the Discord community.

-

Otherwise, go right ahead to the dashboard to get started by logging in with email admin@domain.com and password pass.

+ + +
+
+
+

Title of a longer featured blog post

+

Multiple lines of text that form the lede, informing new readers quickly and + efficiently about what’s most interesting in this post’s contents.

+

Continue reading...

+
+
+ +
+
+
+
+ World +

Featured post

+
Nov 12
+

This is a wider card with supporting text below as a natural + lead-in to additional content.

+ Continue reading +
+
+ +
+
+
+
+
+
+ Design +

Post title

+
Nov 11
+

This is a wider card with supporting text below as a natural lead-in to + additional content.

+ Continue reading +
+
+ +
+
+
+
+ +
+
+

+ From the Firehose +

+ +
+

Sample blog post

+ + +

This blog post shows a few different types of content that’s supported and styled with Bootstrap. + Basic typography, lists, tables, images, code, and more are all supported as expected.

+
+

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+

Blockquotes

+

This is an example blockquote in action:

+
+

Quoted text goes here.

+
+

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+

Example lists

+

This is some additional paragraph placeholder content. It's a slightly shorter version of the + other highly repetitive body text used throughout. This is an example unordered list:

+
    +
  • First list item
  • +
  • Second list item with a longer description
  • +
  • Third list item to close it out
  • +
+

And this is an ordered list:

+
    +
  1. First list item
  2. +
  3. Second list item with a longer description
  4. +
  5. Third list item to close it out
  6. +
+

And this is a definition list:

+
+
HyperText Markup Language (HTML)
+
The language used to describe and define the content of a Web page
+
Cascading Style Sheets (CSS)
+
Used to describe the appearance of Web content
+
JavaScript (JS)
+
The programming language used to build advanced Web sites and applications
+
+

Inline HTML elements

+

HTML defines a long list of available inline tags, a complete list of which can be found on the + Mozilla Developer + Network.

+
    +
  • To bold text, use <strong>.
  • +
  • To italicize text, use <em>.
  • +
  • Abbreviations, like HTML should use <abbr>, with an optional title attribute for the full phrase. +
  • +
  • Citations, like β€” Mark Otto, should use <cite>.
  • +
  • Deleted text should use <del> and inserted + text should use <ins>.
  • +
  • Superscript text uses <sup> and subscript + text uses <sub>. +
  • +
+

Most of these elements are styled by browsers with few modifications on our part.

+

Heading

+

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+

Sub-heading

+

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+
Example code block
+

This is some additional paragraph placeholder content. It's a slightly shorter version of the + other highly repetitive body text used throughout.

+
+ +
+

Another blog post

+ + +

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+
+

Longer quote goes here, maybe with some emphasized text in the middle of it. +

+
+

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+

Example table

+

And don't forget about tables in these posts:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameUpvotesDownvotes
Alice1011
Bob43
Charlie79
Totals2123
+ +

This is some additional paragraph placeholder content. It's a slightly shorter version of the + other highly repetitive body text used throughout.

+
+ +
+

New feature

+ + +

This is some additional paragraph placeholder content. It has been written to fill the available + space and show how a longer snippet of text affects the surrounding content. We'll repeat it + often to keep the demonstration flowing, so be on the lookout for this exact same string of + text.

+
    +
  • First list item
  • +
  • Second list item with a longer description
  • +
  • Third list item to close it out
  • +
+

This is some additional paragraph placeholder content. It's a slightly shorter version of the + other highly repetitive body text used throughout.

+
+ + + +
+ +
+
+
+

About

+

Customize this section to tell your visitors a little bit about your + publication, writers, content, or something else entirely. Totally up to you.

+
+ + + +
+

Elsewhere

+
    +
  1. GitHub
  2. +
  3. Twitter
  4. +
  5. Facebook
  6. +
+
+
+
+
+ +
+ + + + diff --git a/pythoncms/static/themes/front/blogus/page.html b/pythoncms/static/themes/front/blogus/page.html new file mode 100644 index 0000000..129bdaf --- /dev/null +++ b/pythoncms/static/themes/front/blogus/page.html @@ -0,0 +1,15 @@ + + + + + + {{ page.title }} + + + Demo content page, need to add set lang mechanism by calling `/i18n/set-lang?lang=fr`. +

+ {{ page.title }} +

+ {{ page.get_content() }} + + diff --git a/pythoncms/static/themes/front/editorial/LICENSE.txt b/pythoncms/static/themes/front/editorial/LICENSE.txt new file mode 100644 index 0000000..d447b56 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/LICENSE.txt @@ -0,0 +1,63 @@ +Creative Commons Attribution 3.0 Unported +http://creativecommons.org/licenses/by/3.0/ + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +1. Definitions + + 1. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + 2. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. + 3. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. + 4. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + 5. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + 6. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + 7. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + 8. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + 9. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + + 1. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; + 2. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; + 3. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, + 4. to Distribute and Publicly Perform Adaptations. + 5. + + For the avoidance of doubt: + 1. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + 2. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, + 3. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + + 1. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested. + 2. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. + 3. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + 1. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. + 2. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + +8. Miscellaneous + + 1. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + 2. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + 3. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + 4. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + 5. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + 6. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. diff --git a/pythoncms/static/themes/front/editorial/README.txt b/pythoncms/static/themes/front/editorial/README.txt new file mode 100644 index 0000000..5893f5b --- /dev/null +++ b/pythoncms/static/themes/front/editorial/README.txt @@ -0,0 +1,30 @@ +Editorial by HTML5 UP +html5up.net | @ajlkn +Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) + + +Say hello to Editorial, a blog/magazine-ish template built around a toggleable "locking" +sidebar (scroll down to see what I mean) and an accordion-style menu. Not the usual landing +page/portfolio affair you'd expect to see at HTML5 UP, but I figured for my 41st (!!!) +template I'd change it up a little. Enjoy :) + +Demo images* courtesy of Unsplash, a radtastic collection of CC0 (public domain) images +you can use for pretty much whatever. + +(* = not included) + +AJ +aj@lkn.io | @ajlkn + + +Credits: + + Demo Images: + Unsplash (unsplash.com) + + Icons: + Font Awesome (fontawesome.io) + + Other: + jQuery (jquery.com) + Responsive Tools (github.com/ajlkn/responsive-tools) diff --git a/pythoncms/static/themes/front/editorial/assets/css/fontawesome-all.min.css b/pythoncms/static/themes/front/editorial/assets/css/fontawesome-all.min.css new file mode 100644 index 0000000..96766f3 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/css/fontawesome-all.min.css @@ -0,0 +1,101 @@ +/*! + * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} diff --git a/pythoncms/static/themes/front/editorial/assets/css/main.css b/pythoncms/static/themes/front/editorial/assets/css/main.css new file mode 100644 index 0000000..5d5d6aa --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/css/main.css @@ -0,0 +1,2273 @@ +@import url(fontawesome-all.min.css); +@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,600,400italic,600italic|Roboto+Slab:400,700"); +/* + Editorial by HTML5 UP + html5up.net | @ajlkn + Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +*/ +html, body, div, span, applet, object, +iframe, h1, h2, h3, h4, h5, h6, p, blockquote, +pre, a, abbr, acronym, address, big, cite, +code, del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, b, +u, i, center, dl, dt, dd, ol, ul, li, fieldset, +form, label, legend, table, caption, tbody, +tfoot, thead, tr, th, td, article, aside, +canvas, details, embed, figure, figcaption, +footer, header, hgroup, menu, nav, output, ruby, +section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; } + +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; } + +body { + line-height: 1; } + +ol, ul { + list-style: none; } + +blockquote, q { + quotes: none; } + blockquote:before, blockquote:after, q:before, q:after { + content: ''; + content: none; } + +table { + border-collapse: collapse; + border-spacing: 0; } + +body { + -webkit-text-size-adjust: none; } + +mark { + background-color: transparent; + color: inherit; } + +input::-moz-focus-inner { + border: 0; + padding: 0; } + +input, select, textarea { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; } + +/* Basic */ +@-ms-viewport { + width: device-width; } + +body { + -ms-overflow-style: scrollbar; } + +@media screen and (max-width: 480px) { + html, body { + min-width: 320px; } } + +html { + box-sizing: border-box; } + +*, *:before, *:after { + box-sizing: inherit; } + +body { + background: #ffffff; } + body.is-preload *, body.is-preload *:before, body.is-preload *:after, body.is-resizing *, body.is-resizing *:before, body.is-resizing *:after { + -moz-animation: none !important; + -webkit-animation: none !important; + -ms-animation: none !important; + animation: none !important; + -moz-transition: none !important; + -webkit-transition: none !important; + -ms-transition: none !important; + transition: none !important; } + +/* Type */ +body, input, select, textarea { + color: #7f888f; + font-family: "Open Sans", sans-serif; + font-size: 13pt; + font-weight: 400; + line-height: 1.65; } + @media screen and (max-width: 1680px) { + body, input, select, textarea { + font-size: 11pt; } } + @media screen and (max-width: 1280px) { + body, input, select, textarea { + font-size: 10pt; } } + @media screen and (max-width: 360px) { + body, input, select, textarea { + font-size: 9pt; } } + +a { + -moz-transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out; + -webkit-transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out; + transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out; + border-bottom: dotted 1px; + color: #f56a6a; + text-decoration: none; } + a:hover { + border-bottom-color: #f56a6a; + color: #f56a6a !important; } + a:hover strong { + color: inherit; } + +strong, b { + color: #3d4449; + font-weight: 600; } + +em, i { + font-style: italic; } + +p { + margin: 0 0 2em 0; } + +h1, h2, h3, h4, h5, h6 { + color: #3d4449; + font-family: "Roboto Slab", serif; + font-weight: 700; + line-height: 1.5; + margin: 0 0 1em 0; } + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { + color: inherit; + text-decoration: none; + border-bottom: 0; } + +h1 { + font-size: 4em; + margin: 0 0 0.5em 0; + line-height: 1.3; } + +h2 { + font-size: 1.75em; } + +h3 { + font-size: 1.25em; } + +h4 { + font-size: 1.1em; } + +h5 { + font-size: 0.9em; } + +h6 { + font-size: 0.7em; } + +@media screen and (max-width: 1680px) { + h1 { + font-size: 3.5em; } } + +@media screen and (max-width: 980px) { + h1 { + font-size: 3.25em; } } + +@media screen and (max-width: 736px) { + h1 { + font-size: 2em; + line-height: 1.4; } + h2 { + font-size: 1.5em; } } + +sub { + font-size: 0.8em; + position: relative; + top: 0.5em; } + +sup { + font-size: 0.8em; + position: relative; + top: -0.5em; } + +blockquote { + border-left: solid 3px rgba(210, 215, 217, 0.75); + font-style: italic; + margin: 0 0 2em 0; + padding: 0.5em 0 0.5em 2em; } + +code { + background: rgba(230, 235, 237, 0.25); + border-radius: 0.375em; + border: solid 1px rgba(210, 215, 217, 0.75); + font-family: "Courier New", monospace; + font-size: 0.9em; + margin: 0 0.25em; + padding: 0.25em 0.65em; } + +pre { + -webkit-overflow-scrolling: touch; + font-family: "Courier New", monospace; + font-size: 0.9em; + margin: 0 0 2em 0; } + pre code { + display: block; + line-height: 1.75; + padding: 1em 1.5em; + overflow-x: auto; } + +hr { + border: 0; + border-bottom: solid 1px rgba(210, 215, 217, 0.75); + margin: 2em 0; } + hr.major { + margin: 3em 0; } + +.align-left { + text-align: left; } + +.align-center { + text-align: center; } + +.align-right { + text-align: right; } + +/* Row */ +.row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; } + .row > * { + box-sizing: border-box; } + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; } + .row.aln-left { + justify-content: flex-start; } + .row.aln-center { + justify-content: center; } + .row.aln-right { + justify-content: flex-end; } + .row.aln-top { + align-items: flex-start; } + .row.aln-middle { + align-items: center; } + .row.aln-bottom { + align-items: flex-end; } + .row > .imp { + order: -1; } + .row > .col-1 { + width: 8.33333%; } + .row > .off-1 { + margin-left: 8.33333%; } + .row > .col-2 { + width: 16.66667%; } + .row > .off-2 { + margin-left: 16.66667%; } + .row > .col-3 { + width: 25%; } + .row > .off-3 { + margin-left: 25%; } + .row > .col-4 { + width: 33.33333%; } + .row > .off-4 { + margin-left: 33.33333%; } + .row > .col-5 { + width: 41.66667%; } + .row > .off-5 { + margin-left: 41.66667%; } + .row > .col-6 { + width: 50%; } + .row > .off-6 { + margin-left: 50%; } + .row > .col-7 { + width: 58.33333%; } + .row > .off-7 { + margin-left: 58.33333%; } + .row > .col-8 { + width: 66.66667%; } + .row > .off-8 { + margin-left: 66.66667%; } + .row > .col-9 { + width: 75%; } + .row > .off-9 { + margin-left: 75%; } + .row > .col-10 { + width: 83.33333%; } + .row > .off-10 { + margin-left: 83.33333%; } + .row > .col-11 { + width: 91.66667%; } + .row > .off-11 { + margin-left: 91.66667%; } + .row > .col-12 { + width: 100%; } + .row > .off-12 { + margin-left: 100%; } + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; } + .row.gtr-0 > * { + padding: 0 0 0 0em; } + .row.gtr-0.gtr-uniform { + margin-top: 0em; } + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; } + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; } + .row.gtr-25 > * { + padding: 0 0 0 0.375em; } + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; } + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; } + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; } + .row.gtr-50 > * { + padding: 0 0 0 0.75em; } + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; } + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; } + .row { + margin-top: 0; + margin-left: -1.5em; } + .row > * { + padding: 0 0 0 1.5em; } + .row.gtr-uniform { + margin-top: -1.5em; } + .row.gtr-uniform > * { + padding-top: 1.5em; } + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; } + .row.gtr-150 > * { + padding: 0 0 0 2.25em; } + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; } + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; } + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; } + .row.gtr-200 > * { + padding: 0 0 0 3em; } + .row.gtr-200.gtr-uniform { + margin-top: -3em; } + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; } + @media screen and (max-width: 1680px) { + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; } + .row > * { + box-sizing: border-box; } + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; } + .row.aln-left { + justify-content: flex-start; } + .row.aln-center { + justify-content: center; } + .row.aln-right { + justify-content: flex-end; } + .row.aln-top { + align-items: flex-start; } + .row.aln-middle { + align-items: center; } + .row.aln-bottom { + align-items: flex-end; } + .row > .imp-xlarge { + order: -1; } + .row > .col-1-xlarge { + width: 8.33333%; } + .row > .off-1-xlarge { + margin-left: 8.33333%; } + .row > .col-2-xlarge { + width: 16.66667%; } + .row > .off-2-xlarge { + margin-left: 16.66667%; } + .row > .col-3-xlarge { + width: 25%; } + .row > .off-3-xlarge { + margin-left: 25%; } + .row > .col-4-xlarge { + width: 33.33333%; } + .row > .off-4-xlarge { + margin-left: 33.33333%; } + .row > .col-5-xlarge { + width: 41.66667%; } + .row > .off-5-xlarge { + margin-left: 41.66667%; } + .row > .col-6-xlarge { + width: 50%; } + .row > .off-6-xlarge { + margin-left: 50%; } + .row > .col-7-xlarge { + width: 58.33333%; } + .row > .off-7-xlarge { + margin-left: 58.33333%; } + .row > .col-8-xlarge { + width: 66.66667%; } + .row > .off-8-xlarge { + margin-left: 66.66667%; } + .row > .col-9-xlarge { + width: 75%; } + .row > .off-9-xlarge { + margin-left: 75%; } + .row > .col-10-xlarge { + width: 83.33333%; } + .row > .off-10-xlarge { + margin-left: 83.33333%; } + .row > .col-11-xlarge { + width: 91.66667%; } + .row > .off-11-xlarge { + margin-left: 91.66667%; } + .row > .col-12-xlarge { + width: 100%; } + .row > .off-12-xlarge { + margin-left: 100%; } + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; } + .row.gtr-0 > * { + padding: 0 0 0 0em; } + .row.gtr-0.gtr-uniform { + margin-top: 0em; } + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; } + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; } + .row.gtr-25 > * { + padding: 0 0 0 0.375em; } + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; } + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; } + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; } + .row.gtr-50 > * { + padding: 0 0 0 0.75em; } + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; } + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; } + .row { + margin-top: 0; + margin-left: -1.5em; } + .row > * { + padding: 0 0 0 1.5em; } + .row.gtr-uniform { + margin-top: -1.5em; } + .row.gtr-uniform > * { + padding-top: 1.5em; } + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; } + .row.gtr-150 > * { + padding: 0 0 0 2.25em; } + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; } + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; } + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; } + .row.gtr-200 > * { + padding: 0 0 0 3em; } + .row.gtr-200.gtr-uniform { + margin-top: -3em; } + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; } } + @media screen and (max-width: 1280px) { + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; } + .row > * { + box-sizing: border-box; } + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; } + .row.aln-left { + justify-content: flex-start; } + .row.aln-center { + justify-content: center; } + .row.aln-right { + justify-content: flex-end; } + .row.aln-top { + align-items: flex-start; } + .row.aln-middle { + align-items: center; } + .row.aln-bottom { + align-items: flex-end; } + .row > .imp-large { + order: -1; } + .row > .col-1-large { + width: 8.33333%; } + .row > .off-1-large { + margin-left: 8.33333%; } + .row > .col-2-large { + width: 16.66667%; } + .row > .off-2-large { + margin-left: 16.66667%; } + .row > .col-3-large { + width: 25%; } + .row > .off-3-large { + margin-left: 25%; } + .row > .col-4-large { + width: 33.33333%; } + .row > .off-4-large { + margin-left: 33.33333%; } + .row > .col-5-large { + width: 41.66667%; } + .row > .off-5-large { + margin-left: 41.66667%; } + .row > .col-6-large { + width: 50%; } + .row > .off-6-large { + margin-left: 50%; } + .row > .col-7-large { + width: 58.33333%; } + .row > .off-7-large { + margin-left: 58.33333%; } + .row > .col-8-large { + width: 66.66667%; } + .row > .off-8-large { + margin-left: 66.66667%; } + .row > .col-9-large { + width: 75%; } + .row > .off-9-large { + margin-left: 75%; } + .row > .col-10-large { + width: 83.33333%; } + .row > .off-10-large { + margin-left: 83.33333%; } + .row > .col-11-large { + width: 91.66667%; } + .row > .off-11-large { + margin-left: 91.66667%; } + .row > .col-12-large { + width: 100%; } + .row > .off-12-large { + margin-left: 100%; } + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; } + .row.gtr-0 > * { + padding: 0 0 0 0em; } + .row.gtr-0.gtr-uniform { + margin-top: 0em; } + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; } + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; } + .row.gtr-25 > * { + padding: 0 0 0 0.375em; } + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; } + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; } + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; } + .row.gtr-50 > * { + padding: 0 0 0 0.75em; } + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; } + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; } + .row { + margin-top: 0; + margin-left: -1.5em; } + .row > * { + padding: 0 0 0 1.5em; } + .row.gtr-uniform { + margin-top: -1.5em; } + .row.gtr-uniform > * { + padding-top: 1.5em; } + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; } + .row.gtr-150 > * { + padding: 0 0 0 2.25em; } + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; } + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; } + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; } + .row.gtr-200 > * { + padding: 0 0 0 3em; } + .row.gtr-200.gtr-uniform { + margin-top: -3em; } + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; } } + @media screen and (max-width: 980px) { + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; } + .row > * { + box-sizing: border-box; } + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; } + .row.aln-left { + justify-content: flex-start; } + .row.aln-center { + justify-content: center; } + .row.aln-right { + justify-content: flex-end; } + .row.aln-top { + align-items: flex-start; } + .row.aln-middle { + align-items: center; } + .row.aln-bottom { + align-items: flex-end; } + .row > .imp-medium { + order: -1; } + .row > .col-1-medium { + width: 8.33333%; } + .row > .off-1-medium { + margin-left: 8.33333%; } + .row > .col-2-medium { + width: 16.66667%; } + .row > .off-2-medium { + margin-left: 16.66667%; } + .row > .col-3-medium { + width: 25%; } + .row > .off-3-medium { + margin-left: 25%; } + .row > .col-4-medium { + width: 33.33333%; } + .row > .off-4-medium { + margin-left: 33.33333%; } + .row > .col-5-medium { + width: 41.66667%; } + .row > .off-5-medium { + margin-left: 41.66667%; } + .row > .col-6-medium { + width: 50%; } + .row > .off-6-medium { + margin-left: 50%; } + .row > .col-7-medium { + width: 58.33333%; } + .row > .off-7-medium { + margin-left: 58.33333%; } + .row > .col-8-medium { + width: 66.66667%; } + .row > .off-8-medium { + margin-left: 66.66667%; } + .row > .col-9-medium { + width: 75%; } + .row > .off-9-medium { + margin-left: 75%; } + .row > .col-10-medium { + width: 83.33333%; } + .row > .off-10-medium { + margin-left: 83.33333%; } + .row > .col-11-medium { + width: 91.66667%; } + .row > .off-11-medium { + margin-left: 91.66667%; } + .row > .col-12-medium { + width: 100%; } + .row > .off-12-medium { + margin-left: 100%; } + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; } + .row.gtr-0 > * { + padding: 0 0 0 0em; } + .row.gtr-0.gtr-uniform { + margin-top: 0em; } + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; } + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; } + .row.gtr-25 > * { + padding: 0 0 0 0.375em; } + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; } + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; } + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; } + .row.gtr-50 > * { + padding: 0 0 0 0.75em; } + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; } + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; } + .row { + margin-top: 0; + margin-left: -1.5em; } + .row > * { + padding: 0 0 0 1.5em; } + .row.gtr-uniform { + margin-top: -1.5em; } + .row.gtr-uniform > * { + padding-top: 1.5em; } + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; } + .row.gtr-150 > * { + padding: 0 0 0 2.25em; } + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; } + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; } + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; } + .row.gtr-200 > * { + padding: 0 0 0 3em; } + .row.gtr-200.gtr-uniform { + margin-top: -3em; } + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; } } + @media screen and (max-width: 736px) { + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; } + .row > * { + box-sizing: border-box; } + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; } + .row.aln-left { + justify-content: flex-start; } + .row.aln-center { + justify-content: center; } + .row.aln-right { + justify-content: flex-end; } + .row.aln-top { + align-items: flex-start; } + .row.aln-middle { + align-items: center; } + .row.aln-bottom { + align-items: flex-end; } + .row > .imp-small { + order: -1; } + .row > .col-1-small { + width: 8.33333%; } + .row > .off-1-small { + margin-left: 8.33333%; } + .row > .col-2-small { + width: 16.66667%; } + .row > .off-2-small { + margin-left: 16.66667%; } + .row > .col-3-small { + width: 25%; } + .row > .off-3-small { + margin-left: 25%; } + .row > .col-4-small { + width: 33.33333%; } + .row > .off-4-small { + margin-left: 33.33333%; } + .row > .col-5-small { + width: 41.66667%; } + .row > .off-5-small { + margin-left: 41.66667%; } + .row > .col-6-small { + width: 50%; } + .row > .off-6-small { + margin-left: 50%; } + .row > .col-7-small { + width: 58.33333%; } + .row > .off-7-small { + margin-left: 58.33333%; } + .row > .col-8-small { + width: 66.66667%; } + .row > .off-8-small { + margin-left: 66.66667%; } + .row > .col-9-small { + width: 75%; } + .row > .off-9-small { + margin-left: 75%; } + .row > .col-10-small { + width: 83.33333%; } + .row > .off-10-small { + margin-left: 83.33333%; } + .row > .col-11-small { + width: 91.66667%; } + .row > .off-11-small { + margin-left: 91.66667%; } + .row > .col-12-small { + width: 100%; } + .row > .off-12-small { + margin-left: 100%; } + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; } + .row.gtr-0 > * { + padding: 0 0 0 0em; } + .row.gtr-0.gtr-uniform { + margin-top: 0em; } + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; } + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; } + .row.gtr-25 > * { + padding: 0 0 0 0.375em; } + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; } + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; } + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; } + .row.gtr-50 > * { + padding: 0 0 0 0.75em; } + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; } + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; } + .row { + margin-top: 0; + margin-left: -1.5em; } + .row > * { + padding: 0 0 0 1.5em; } + .row.gtr-uniform { + margin-top: -1.5em; } + .row.gtr-uniform > * { + padding-top: 1.5em; } + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; } + .row.gtr-150 > * { + padding: 0 0 0 2.25em; } + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; } + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; } + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; } + .row.gtr-200 > * { + padding: 0 0 0 3em; } + .row.gtr-200.gtr-uniform { + margin-top: -3em; } + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; } } + @media screen and (max-width: 480px) { + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; } + .row > * { + box-sizing: border-box; } + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; } + .row.aln-left { + justify-content: flex-start; } + .row.aln-center { + justify-content: center; } + .row.aln-right { + justify-content: flex-end; } + .row.aln-top { + align-items: flex-start; } + .row.aln-middle { + align-items: center; } + .row.aln-bottom { + align-items: flex-end; } + .row > .imp-xsmall { + order: -1; } + .row > .col-1-xsmall { + width: 8.33333%; } + .row > .off-1-xsmall { + margin-left: 8.33333%; } + .row > .col-2-xsmall { + width: 16.66667%; } + .row > .off-2-xsmall { + margin-left: 16.66667%; } + .row > .col-3-xsmall { + width: 25%; } + .row > .off-3-xsmall { + margin-left: 25%; } + .row > .col-4-xsmall { + width: 33.33333%; } + .row > .off-4-xsmall { + margin-left: 33.33333%; } + .row > .col-5-xsmall { + width: 41.66667%; } + .row > .off-5-xsmall { + margin-left: 41.66667%; } + .row > .col-6-xsmall { + width: 50%; } + .row > .off-6-xsmall { + margin-left: 50%; } + .row > .col-7-xsmall { + width: 58.33333%; } + .row > .off-7-xsmall { + margin-left: 58.33333%; } + .row > .col-8-xsmall { + width: 66.66667%; } + .row > .off-8-xsmall { + margin-left: 66.66667%; } + .row > .col-9-xsmall { + width: 75%; } + .row > .off-9-xsmall { + margin-left: 75%; } + .row > .col-10-xsmall { + width: 83.33333%; } + .row > .off-10-xsmall { + margin-left: 83.33333%; } + .row > .col-11-xsmall { + width: 91.66667%; } + .row > .off-11-xsmall { + margin-left: 91.66667%; } + .row > .col-12-xsmall { + width: 100%; } + .row > .off-12-xsmall { + margin-left: 100%; } + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; } + .row.gtr-0 > * { + padding: 0 0 0 0em; } + .row.gtr-0.gtr-uniform { + margin-top: 0em; } + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; } + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; } + .row.gtr-25 > * { + padding: 0 0 0 0.375em; } + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; } + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; } + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; } + .row.gtr-50 > * { + padding: 0 0 0 0.75em; } + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; } + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; } + .row { + margin-top: 0; + margin-left: -1.5em; } + .row > * { + padding: 0 0 0 1.5em; } + .row.gtr-uniform { + margin-top: -1.5em; } + .row.gtr-uniform > * { + padding-top: 1.5em; } + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; } + .row.gtr-150 > * { + padding: 0 0 0 2.25em; } + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; } + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; } + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; } + .row.gtr-200 > * { + padding: 0 0 0 3em; } + .row.gtr-200.gtr-uniform { + margin-top: -3em; } + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; } } + +/* Section/Article */ +section.special, article.special { + text-align: center; } + +header p { + font-family: "Roboto Slab", serif; + font-size: 1em; + font-weight: 400; + letter-spacing: 0.075em; + margin-top: -0.5em; + text-transform: uppercase; } + +header.major > :last-child { + border-bottom: solid 3px #f56a6a; + display: inline-block; + margin: 0 0 2em 0; + padding: 0 0.75em 0.5em 0; } + +header.main > :last-child { + margin: 0 0 1em 0; } + +/* Form */ +form { + margin: 0 0 2em 0; } + +label { + color: #3d4449; + display: block; + font-size: 0.9em; + font-weight: 600; + margin: 0 0 1em 0; } + +input[type="text"], +input[type="password"], +input[type="email"], +input[type="tel"], +input[type="search"], +input[type="url"], +select, +textarea { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + background: #ffffff; + border-radius: 0.375em; + border: none; + border: solid 1px rgba(210, 215, 217, 0.75); + color: inherit; + display: block; + outline: 0; + padding: 0 1em; + text-decoration: none; + width: 100%; } + input[type="text"]:invalid, + input[type="password"]:invalid, + input[type="email"]:invalid, + input[type="tel"]:invalid, + input[type="search"]:invalid, + input[type="url"]:invalid, + select:invalid, + textarea:invalid { + box-shadow: none; } + input[type="text"]:focus, + input[type="password"]:focus, + input[type="email"]:focus, + input[type="tel"]:focus, + input[type="search"]:focus, + input[type="url"]:focus, + select:focus, + textarea:focus { + border-color: #f56a6a; + box-shadow: 0 0 0 1px #f56a6a; } + +select { + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' preserveAspectRatio='none' viewBox='0 0 40 40'%3E%3Cpath d='M9.4,12.3l10.4,10.4l10.4-10.4c0.2-0.2,0.5-0.4,0.9-0.4c0.3,0,0.6,0.1,0.9,0.4l3.3,3.3c0.2,0.2,0.4,0.5,0.4,0.9 c0,0.4-0.1,0.6-0.4,0.9L20.7,31.9c-0.2,0.2-0.5,0.4-0.9,0.4c-0.3,0-0.6-0.1-0.9-0.4L4.3,17.3c-0.2-0.2-0.4-0.5-0.4-0.9 c0-0.4,0.1-0.6,0.4-0.9l3.3-3.3c0.2-0.2,0.5-0.4,0.9-0.4S9.1,12.1,9.4,12.3z' fill='rgba(210, 215, 217, 0.75)' /%3E%3C/svg%3E"); + background-size: 1.25em; + background-repeat: no-repeat; + background-position: calc(100% - 1em) center; + height: 2.75em; + padding-right: 2.75em; + text-overflow: ellipsis; } + select option { + color: #3d4449; + background: #ffffff; } + select:focus::-ms-value { + background-color: transparent; } + select::-ms-expand { + display: none; } + +input[type="text"], +input[type="password"], +input[type="email"], +input[type="tel"], +input[type="search"], +input[type="url"], +select { + height: 2.75em; } + +textarea { + padding: 0.75em 1em; } + +input[type="checkbox"], +input[type="radio"] { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + display: block; + float: left; + margin-right: -2em; + opacity: 0; + width: 1em; + z-index: -1; } + input[type="checkbox"] + label, + input[type="radio"] + label { + text-decoration: none; + color: #7f888f; + cursor: pointer; + display: inline-block; + font-size: 1em; + font-weight: 400; + padding-left: 2.4em; + padding-right: 0.75em; + position: relative; } + input[type="checkbox"] + label:before, + input[type="radio"] + label:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } + input[type="checkbox"] + label:before, + input[type="radio"] + label:before { + background: #ffffff; + border-radius: 0.375em; + border: solid 1px rgba(210, 215, 217, 0.75); + content: ''; + display: inline-block; + font-size: 0.8em; + height: 2.0625em; + left: 0; + line-height: 2.0625em; + position: absolute; + text-align: center; + top: 0; + width: 2.0625em; } + input[type="checkbox"]:checked + label:before, + input[type="radio"]:checked + label:before { + background: #3d4449; + border-color: #3d4449; + color: #ffffff; + content: '\f00c'; } + input[type="checkbox"]:focus + label:before, + input[type="radio"]:focus + label:before { + border-color: #f56a6a; + box-shadow: 0 0 0 1px #f56a6a; } + +input[type="checkbox"] + label:before { + border-radius: 0.375em; } + +input[type="radio"] + label:before { + border-radius: 100%; } + +::-webkit-input-placeholder { + color: #9fa3a6 !important; + opacity: 1.0; } + +:-moz-placeholder { + color: #9fa3a6 !important; + opacity: 1.0; } + +::-moz-placeholder { + color: #9fa3a6 !important; + opacity: 1.0; } + +:-ms-input-placeholder { + color: #9fa3a6 !important; + opacity: 1.0; } + +/* Box */ +.box { + border-radius: 0.375em; + border: solid 1px rgba(210, 215, 217, 0.75); + margin-bottom: 2em; + padding: 1.5em; } + .box > :last-child, + .box > :last-child > :last-child, + .box > :last-child > :last-child > :last-child { + margin-bottom: 0; } + .box.alt { + border: 0; + border-radius: 0; + padding: 0; } + +/* Icon */ +.icon { + text-decoration: none; + border-bottom: none; + position: relative; } + .icon:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + .icon > .label { + display: none; } + .icon:before { + line-height: inherit; } + .icon.solid:before { + font-weight: 900; } + .icon.brands:before { + font-family: 'Font Awesome 5 Brands'; } + +/* Image */ +.image { + border-radius: 0.375em; + border: 0; + display: inline-block; + position: relative; } + .image img { + border-radius: 0.375em; + display: block; } + .image.left, .image.right { + max-width: 40%; } + .image.left img, .image.right img { + width: 100%; } + .image.left { + float: left; + padding: 0 1.5em 1em 0; + top: 0.25em; } + .image.right { + float: right; + padding: 0 0 1em 1.5em; + top: 0.25em; } + .image.fit { + display: block; + margin: 0 0 2em 0; + width: 100%; } + .image.fit img { + width: 100%; } + .image.main { + display: block; + margin: 0 0 3em 0; + width: 100%; } + .image.main img { + width: 100%; } + +a.image { + overflow: hidden; } + a.image img { + -moz-transition: -moz-transform 0.2s ease; + -webkit-transition: -webkit-transform 0.2s ease; + -ms-transition: -ms-transform 0.2s ease; + transition: transform 0.2s ease; } + a.image:hover img { + -moz-transform: scale(1.075); + -webkit-transform: scale(1.075); + -ms-transform: scale(1.075); + transform: scale(1.075); } + +/* List */ +ol { + list-style: decimal; + margin: 0 0 2em 0; + padding-left: 1.25em; } + ol li { + padding-left: 0.25em; } + +ul { + list-style: disc; + margin: 0 0 2em 0; + padding-left: 1em; } + ul li { + padding-left: 0.5em; } + ul.alt { + list-style: none; + padding-left: 0; } + ul.alt li { + border-top: solid 1px rgba(210, 215, 217, 0.75); + padding: 0.5em 0; } + ul.alt li:first-child { + border-top: 0; + padding-top: 0; } + +dl { + margin: 0 0 2em 0; } + dl dt { + display: block; + font-weight: 600; + margin: 0 0 1em 0; } + dl dd { + margin-left: 2em; } + +/* Actions */ +ul.actions { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + cursor: default; + list-style: none; + margin-left: -1em; + padding-left: 0; } + ul.actions li { + padding: 0 0 0 1em; + vertical-align: middle; } + ul.actions.special { + -moz-justify-content: center; + -webkit-justify-content: center; + -ms-justify-content: center; + justify-content: center; + width: 100%; + margin-left: 0; } + ul.actions.special li:first-child { + padding-left: 0; } + ul.actions.stacked { + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + margin-left: 0; } + ul.actions.stacked li { + padding: 1.3em 0 0 0; } + ul.actions.stacked li:first-child { + padding-top: 0; } + ul.actions.fit { + width: calc(100% + 1em); } + ul.actions.fit li { + -moz-flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex-grow: 1; + flex-grow: 1; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + width: 100%; } + ul.actions.fit li > * { + width: 100%; } + ul.actions.fit.stacked { + width: 100%; } + +/* Icons */ +ul.icons { + cursor: default; + list-style: none; + padding-left: 0; } + ul.icons li { + display: inline-block; + padding: 0 1em 0 0; } + ul.icons li:last-child { + padding-right: 0; } + ul.icons li .icon { + color: inherit; } + ul.icons li .icon:before { + font-size: 1.25em; } + +/* Contact */ +ul.contact { + list-style: none; + padding: 0; } + ul.contact li { + text-decoration: none; + border-top: solid 1px rgba(210, 215, 217, 0.75); + margin: 1.5em 0 0 0; + padding: 1.5em 0 0 3em; + position: relative; } + ul.contact li:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } + ul.contact li:before { + color: #f56a6a; + display: inline-block; + font-size: 1.5em; + height: 1.125em; + left: 0; + line-height: 1.125em; + position: absolute; + text-align: center; + top: 1em; + width: 1.5em; } + ul.contact li:first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; } + ul.contact li:first-child:before { + top: 0; } + ul.contact li a { + color: inherit; } + +/* Pagination */ +ul.pagination { + cursor: default; + list-style: none; + padding-left: 0; } + ul.pagination li { + display: inline-block; + padding-left: 0; + vertical-align: middle; } + ul.pagination li > .page { + -moz-transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + -webkit-transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + -ms-transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + border-bottom: 0; + border-radius: 0.375em; + display: inline-block; + font-size: 0.8em; + font-weight: 600; + height: 2em; + line-height: 2em; + margin: 0 0.125em; + min-width: 2em; + padding: 0 0.5em; + text-align: center; } + ul.pagination li > .page.active { + background-color: #f56a6a; + color: #ffffff !important; } + ul.pagination li > .page.active:hover { + background-color: #f67878; } + ul.pagination li > .page.active:active { + background-color: #f45c5c; } + ul.pagination li:first-child { + padding-right: 0.75em; } + ul.pagination li:last-child { + padding-left: 0.75em; } + @media screen and (max-width: 480px) { + ul.pagination li:nth-child(n+2):nth-last-child(n+2) { + display: none; } + ul.pagination li:first-child { + padding-right: 0; } } + +/* Table */ +.table-wrapper { + -webkit-overflow-scrolling: touch; + overflow-x: auto; } + +table { + margin: 0 0 2em 0; + width: 100%; } + table tbody tr { + border: solid 1px rgba(210, 215, 217, 0.75); + border-left: 0; + border-right: 0; } + table tbody tr:nth-child(2n + 1) { + background-color: rgba(230, 235, 237, 0.25); } + table td { + padding: 0.75em 0.75em; } + table th { + color: #3d4449; + font-size: 0.9em; + font-weight: 600; + padding: 0 0.75em 0.75em 0.75em; + text-align: left; } + table thead { + border-bottom: solid 2px rgba(210, 215, 217, 0.75); } + table tfoot { + border-top: solid 2px rgba(210, 215, 217, 0.75); } + table.alt { + border-collapse: separate; } + table.alt tbody tr td { + border: solid 1px rgba(210, 215, 217, 0.75); + border-left-width: 0; + border-top-width: 0; } + table.alt tbody tr td:first-child { + border-left-width: 1px; } + table.alt tbody tr:first-child td { + border-top-width: 1px; } + table.alt thead { + border-bottom: 0; } + table.alt tfoot { + border-top: 0; } + +/* Button */ +input[type="submit"], +input[type="reset"], +input[type="button"], +button, +.button { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + -moz-transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + -webkit-transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + -ms-transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + background-color: transparent; + border-radius: 0.375em; + border: 0; + box-shadow: inset 0 0 0 2px #f56a6a; + color: #f56a6a !important; + cursor: pointer; + display: inline-block; + font-family: "Roboto Slab", serif; + font-size: 0.8em; + font-weight: 700; + height: 3.5em; + letter-spacing: 0.075em; + line-height: 3.5em; + padding: 0 2.25em; + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; } + input[type="submit"]:hover, + input[type="reset"]:hover, + input[type="button"]:hover, + button:hover, + .button:hover { + background-color: rgba(245, 106, 106, 0.05); } + input[type="submit"]:active, + input[type="reset"]:active, + input[type="button"]:active, + button:active, + .button:active { + background-color: rgba(245, 106, 106, 0.15); } + input[type="submit"].icon:before, + input[type="reset"].icon:before, + input[type="button"].icon:before, + button.icon:before, + .button.icon:before { + margin-right: 0.5em; } + input[type="submit"].fit, + input[type="reset"].fit, + input[type="button"].fit, + button.fit, + .button.fit { + width: 100%; } + input[type="submit"].small, + input[type="reset"].small, + input[type="button"].small, + button.small, + .button.small { + font-size: 0.6em; } + input[type="submit"].large, + input[type="reset"].large, + input[type="button"].large, + button.large, + .button.large { + font-size: 1em; + height: 3.65em; + line-height: 3.65em; } + input[type="submit"].primary, + input[type="reset"].primary, + input[type="button"].primary, + button.primary, + .button.primary { + background-color: #f56a6a; + box-shadow: none; + color: #ffffff !important; } + input[type="submit"].primary:hover, + input[type="reset"].primary:hover, + input[type="button"].primary:hover, + button.primary:hover, + .button.primary:hover { + background-color: #f67878; } + input[type="submit"].primary:active, + input[type="reset"].primary:active, + input[type="button"].primary:active, + button.primary:active, + .button.primary:active { + background-color: #f45c5c; } + input[type="submit"].disabled, input[type="submit"]:disabled, + input[type="reset"].disabled, + input[type="reset"]:disabled, + input[type="button"].disabled, + input[type="button"]:disabled, + button.disabled, + button:disabled, + .button.disabled, + .button:disabled { + pointer-events: none; + opacity: 0.25; } + +/* Mini Posts */ +.mini-posts article { + border-top: solid 1px rgba(210, 215, 217, 0.75); + margin-top: 2em; + padding-top: 2em; } + .mini-posts article .image { + display: block; + margin: 0 0 1.5em 0; } + .mini-posts article .image img { + display: block; + width: 100%; } + .mini-posts article:first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; } + +/* Features */ +.features { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0 0 2em -3em; + width: calc(100% + 3em); } + .features article { + -moz-align-items: center; + -webkit-align-items: center; + -ms-align-items: center; + align-items: center; + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + margin: 0 0 3em 3em; + position: relative; + width: calc(50% - 3em); } + .features article:nth-child(2n - 1) { + margin-right: 1.5em; } + .features article:nth-child(2n) { + margin-left: 1.5em; } + .features article:nth-last-child(1), .features article:nth-last-child(2) { + margin-bottom: 0; } + .features article .icon { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex-shrink: 0; + flex-shrink: 0; + display: block; + height: 10em; + line-height: 10em; + margin: 0 2em 0 0; + text-align: center; + width: 10em; } + .features article .icon:before { + color: #f56a6a; + font-size: 2.75rem; + position: relative; + top: 0.05em; } + .features article .icon:after { + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + border-radius: 0.25rem; + border: solid 2px rgba(210, 215, 217, 0.75); + content: ''; + display: block; + height: 7em; + left: 50%; + margin: -3.5em 0 0 -3.5em; + position: absolute; + top: 50%; + width: 7em; } + .features article .content { + -moz-flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex-grow: 1; + flex-grow: 1; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + width: 100%; } + .features article .content > :last-child { + margin-bottom: 0; } + @media screen and (max-width: 980px) { + .features { + margin: 0 0 2em 0; + width: 100%; } + .features article { + margin: 0 0 3em 0; + width: 100%; } + .features article:nth-child(2n - 1) { + margin-right: 0; } + .features article:nth-child(2n) { + margin-left: 0; } + .features article:nth-last-child(1), .features article:nth-last-child(2) { + margin-bottom: 3em; } + .features article:last-child { + margin-bottom: 0; } + .features article .icon { + height: 8em; + line-height: 8em; + width: 8em; } + .features article .icon:before { + font-size: 2.25rem; } + .features article .icon:after { + height: 6em; + margin: -3em 0 0 -3em; + width: 6em; } } + @media screen and (max-width: 480px) { + .features article { + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -moz-align-items: -moz-flex-start; + -webkit-align-items: -webkit-flex-start; + -ms-align-items: -ms-flex-start; + align-items: flex-start; } + .features article .icon { + height: 6em; + line-height: 6em; + margin: 0 0 1.5em 0; + width: 6em; } + .features article .icon:before { + font-size: 1.5rem; } + .features article .icon:after { + height: 4em; + margin: -2em 0 0 -2em; + width: 4em; } } + @media screen and (max-width: 480px) { + .features article .icon:before { + font-size: 1.25rem; } } + +/* Posts */ +.posts { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0 0 2em -6em; + width: calc(100% + 6em); } + .posts article { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + margin: 0 0 6em 6em; + position: relative; + width: calc(33.33333% - 6em); } + .posts article:before { + background: rgba(210, 215, 217, 0.75); + content: ''; + display: block; + height: calc(100% + 6em); + left: -3em; + position: absolute; + top: 0; + width: 1px; } + .posts article:after { + background: rgba(210, 215, 217, 0.75); + bottom: -3em; + content: ''; + display: block; + height: 1px; + position: absolute; + right: 0; + width: calc(100% + 6em); } + .posts article > :last-child { + margin-bottom: 0; } + .posts article .image { + display: block; + margin: 0 0 2em 0; } + .posts article .image img { + display: block; + width: 100%; } + @media screen and (min-width: 1681px) { + .posts article:nth-child(3n + 1):before { + display: none; } + .posts article:nth-child(3n + 1):after { + width: 100%; } + .posts article:nth-last-child(1), .posts article:nth-last-child(2), .posts article:nth-last-child(3) { + margin-bottom: 0; } + .posts article:nth-last-child(1):before, .posts article:nth-last-child(2):before, .posts article:nth-last-child(3):before { + height: 100%; } + .posts article:nth-last-child(1):after, .posts article:nth-last-child(2):after, .posts article:nth-last-child(3):after { + display: none; } } + @media screen and (max-width: 1680px) { + .posts article { + width: calc(50% - 6em); } + .posts article:nth-last-child(3) { + margin-bottom: 6em; } } + @media screen and (min-width: 481px) and (max-width: 1680px) { + .posts article:nth-child(2n + 1):before { + display: none; } + .posts article:nth-child(2n + 1):after { + width: 100%; } + .posts article:nth-last-child(1), .posts article:nth-last-child(2) { + margin-bottom: 0; } + .posts article:nth-last-child(1):before, .posts article:nth-last-child(2):before { + height: 100%; } + .posts article:nth-last-child(1):after, .posts article:nth-last-child(2):after { + display: none; } } + @media screen and (max-width: 736px) { + .posts { + margin: 0 0 2em -4.5em; + width: calc(100% + 4.5em); } + .posts article { + margin: 0 0 4.5em 4.5em; + width: calc(50% - 4.5em); } + .posts article:before { + height: calc(100% + 4.5em); + left: -2.25em; } + .posts article:after { + bottom: -2.25em; + width: calc(100% + 4.5em); } + .posts article:nth-last-child(3) { + margin-bottom: 4.5em; } } + @media screen and (max-width: 480px) { + .posts { + margin: 0 0 2em 0; + width: 100%; } + .posts article { + margin: 0 0 4.5em 0; + width: 100%; } + .posts article:before { + display: none; } + .posts article:after { + width: 100%; } + .posts article:last-child { + margin-bottom: 0; } + .posts article:last-child:after { + display: none; } } + +/* Wrapper */ +#wrapper { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-direction: row-reverse; + -webkit-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; + min-height: 100vh; } + +/* Main */ +#main { + -moz-flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex-grow: 1; + flex-grow: 1; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + width: 100%; } + #main > .inner { + padding: 0 6em 0.1em 6em ; + margin: 0 auto; + max-width: 110em; } + #main > .inner > section { + padding: 6em 0 4em 0 ; + border-top: solid 2px rgba(210, 215, 217, 0.75); } + #main > .inner > section:first-of-type { + border-top: 0 !important; } + @media screen and (max-width: 1680px) { + #main > .inner { + padding: 0 5em 0.1em 5em ; } + #main > .inner > section { + padding: 5em 0 3em 0 ; } } + @media screen and (max-width: 1280px) { + #main > .inner { + padding: 0 4em 0.1em 4em ; } + #main > .inner > section { + padding: 4em 0 2em 0 ; } } + @media screen and (max-width: 736px) { + #main > .inner { + padding: 0 2em 0.1em 2em ; } + #main > .inner > section { + padding: 3em 0 1em 0 ; } } + +/* Sidebar */ +#search form { + text-decoration: none; + position: relative; } + #search form:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } + #search form:before { + -moz-transform: scaleX(-1); + -webkit-transform: scaleX(-1); + -ms-transform: scaleX(-1); + transform: scaleX(-1); + color: #7f888f; + content: '\f002'; + cursor: default; + display: block; + font-size: 1.5em; + height: 2em; + line-height: 2em; + opacity: 0.325; + position: absolute; + right: 0; + text-align: center; + top: 0; + width: 2em; } + #search form input[type="text"] { + padding-right: 2.75em; } + +#sidebar { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex-shrink: 0; + flex-shrink: 0; + -moz-transition: margin-left 0.5s ease, box-shadow 0.5s ease; + -webkit-transition: margin-left 0.5s ease, box-shadow 0.5s ease; + -ms-transition: margin-left 0.5s ease, box-shadow 0.5s ease; + transition: margin-left 0.5s ease, box-shadow 0.5s ease; + background-color: #f5f6f7; + font-size: 0.9em; + position: relative; + width: 26em; } + #sidebar h2 { + font-size: 1.38889em; } + #sidebar > .inner { + padding: 2.22222em 2.22222em 2.44444em 2.22222em ; + position: relative; + width: 26em; } + #sidebar > .inner > * { + border-bottom: solid 2px rgba(210, 215, 217, 0.75); + margin: 0 0 3.5em 0; + padding: 0 0 3.5em 0; } + #sidebar > .inner > * > :last-child { + margin-bottom: 0; } + #sidebar > .inner > *:last-child { + border-bottom: 0; + margin-bottom: 0; + padding-bottom: 0; } + #sidebar > .inner > .alt { + background-color: #eff1f2; + border-bottom: 0; + margin: -2.22222em 0 4.44444em -2.22222em; + padding: 2.22222em; + width: calc(100% + 4.44444em); } + #sidebar .toggle { + text-decoration: none; + -moz-transition: left 0.5s ease; + -webkit-transition: left 0.5s ease; + -ms-transition: left 0.5s ease; + transition: left 0.5s ease; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + border: 0; + display: block; + height: 7.5em; + left: 26em; + line-height: 7.5em; + outline: 0; + overflow: hidden; + position: absolute; + text-align: center; + text-indent: -15em; + white-space: nowrap; + top: 0; + width: 6em; + z-index: 10000; } + #sidebar .toggle:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } + #sidebar .toggle:before { + content: '\f0c9'; + font-size: 2rem; + height: inherit; + left: 0; + line-height: inherit; + position: absolute; + text-indent: 0; + top: 0; + width: inherit; } + #sidebar.inactive { + margin-left: -26em; } + @media screen and (max-width: 1680px) { + #sidebar { + width: 24em; } + #sidebar > .inner { + padding: 1.66667em 1.66667em 1.33333em 1.66667em ; + width: 24em; } + #sidebar > .inner > .alt { + margin: -1.66667em 0 3.33333em -1.66667em; + padding: 1.66667em; + width: calc(100% + 3.33333em); } + #sidebar .toggle { + height: 6.25em; + left: 24em; + line-height: 6.25em; + text-indent: 5em; + width: 5em; } + #sidebar .toggle:before { + font-size: 1.5rem; } + #sidebar.inactive { + margin-left: -24em; } } + @media screen and (max-width: 1280px) { + #sidebar { + box-shadow: 0 0 5em 0 rgba(0, 0, 0, 0.175); + height: 100%; + left: 0; + position: fixed; + top: 0; + z-index: 10000; } + #sidebar.inactive { + box-shadow: none; } + #sidebar > .inner { + -webkit-overflow-scrolling: touch; + height: 100%; + left: 0; + overflow-x: hidden; + overflow-y: auto; + position: absolute; + top: 0; } + #sidebar > .inner:after { + content: ''; + display: block; + height: 4em; + width: 100%; } + #sidebar .toggle { + text-indent: 6em; + width: 6em; } + #sidebar .toggle:before { + font-size: 1.5rem; + margin-left: -0.4375em; } + body.is-preload #sidebar { + display: none; } } + @media screen and (max-width: 736px) { + #sidebar .toggle { + text-indent: 7.25em; + width: 7.25em; } + #sidebar .toggle:before { + color: #7f888f; + margin-left: -0.0625em; + margin-top: -0.25em; + font-size: 1.1rem; + z-index: 1; } + #sidebar .toggle:after { + background: rgba(222, 225, 226, 0.75); + border-radius: 0.375em; + content: ''; + height: 3.5em; + left: 1em; + position: absolute; + top: 1em; + width: 5em; } } + +/* Header */ +#header { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + border-bottom: solid 5px #f56a6a; + padding: 6em 0 1em 0; + position: relative; } + #header > * { + -moz-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 0; } + #header .logo { + border-bottom: 0; + color: inherit; + font-family: "Roboto Slab", serif; + font-size: 1.125em; } + #header .icons { + text-align: right; } + @media screen and (max-width: 1680px) { + #header { + padding-top: 5em; } } + @media screen and (max-width: 736px) { + #header { + padding-top: 6.5em; } + #header .logo { + font-size: 1.25em; + margin: 0; } + #header .icons { + height: 5em; + line-height: 5em; + position: absolute; + right: -0.5em; + top: 0; } } + +/* Banner */ +#banner { + padding: 6em 0 4em 0 ; + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; } + #banner h1 { + margin-top: -0.125em; } + #banner .content { + -moz-flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex-grow: 1; + flex-grow: 1; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + width: 50%; } + #banner .image { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex-shrink: 0; + flex-shrink: 0; + display: block; + margin: 0 0 2em 4em; + width: 50%; } + #banner .image img { + height: 100%; + -moz-object-fit: cover; + -webkit-object-fit: cover; + -ms-object-fit: cover; + object-fit: cover; + -moz-object-position: center; + -webkit-object-position: center; + -ms-object-position: center; + object-position: center; + width: 100%; } + @media screen and (orientation: portrait) { + #banner { + -moz-flex-direction: column-reverse; + -webkit-flex-direction: column-reverse; + -ms-flex-direction: column-reverse; + flex-direction: column-reverse; } + #banner h1 br { + display: none; } + #banner .content { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex-shrink: 0; + flex-shrink: 0; + width: 100%; } + #banner .image { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex-shrink: 0; + flex-shrink: 0; + margin: 0 0 4em 0; + height: 25em; + max-height: 50vh; + min-height: 18em; + width: 100%; } } + @media screen and (orientation: portrait) and (max-width: 480px) { + #banner .image { + max-height: 35vh; } } + +/* Footer */ +#footer .copyright { + color: #9fa3a6; + font-size: 0.9em; } + #footer .copyright a { + color: inherit; } + +/* Menu */ +#menu ul { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + color: #3d4449; + font-family: "Roboto Slab", serif; + font-weight: 400; + letter-spacing: 0.075em; + list-style: none; + margin-bottom: 0; + padding: 0; + text-transform: uppercase; } + #menu ul a, #menu ul span { + border-bottom: 0; + color: inherit; + cursor: pointer; + display: block; + font-size: 0.9em; + padding: 0.625em 0; } + #menu ul a:hover, #menu ul span:hover { + color: #f56a6a; } + #menu ul a.opener, #menu ul span.opener { + -moz-transition: color 0.2s ease-in-out; + -webkit-transition: color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out; + transition: color 0.2s ease-in-out; + text-decoration: none; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + position: relative; } + #menu ul a.opener:before, #menu ul span.opener:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } + #menu ul a.opener:before, #menu ul span.opener:before { + -moz-transition: color 0.2s ease-in-out, -moz-transform 0.2s ease-in-out; + -webkit-transition: color 0.2s ease-in-out, -webkit-transform 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out, -ms-transform 0.2s ease-in-out; + transition: color 0.2s ease-in-out, transform 0.2s ease-in-out; + color: #9fa3a6; + content: '\f078'; + position: absolute; + right: 0; } + #menu ul a.opener:hover:before, #menu ul span.opener:hover:before { + color: #f56a6a; } + #menu ul a.opener.active + ul, #menu ul span.opener.active + ul { + display: block; } + #menu ul a.opener.active:before, #menu ul span.opener.active:before { + -moz-transform: rotate(-180deg); + -webkit-transform: rotate(-180deg); + -ms-transform: rotate(-180deg); + transform: rotate(-180deg); } + +#menu > ul > li { + border-top: solid 1px rgba(210, 215, 217, 0.75); + margin: 0.5em 0 0 0; + padding: 0.5em 0 0 0; } + #menu > ul > li > ul { + color: #9fa3a6; + display: none; + margin: 0.5em 0 1.5em 0; + padding-left: 1em; } + #menu > ul > li > ul a, #menu > ul > li > ul span { + font-size: 0.8em; } + #menu > ul > li > ul > li { + margin: 0.125em 0 0 0; + padding: 0.125em 0 0 0; } + #menu > ul > li:first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; } diff --git a/pythoncms/static/themes/front/editorial/assets/js/breakpoints.min.js b/pythoncms/static/themes/front/editorial/assets/js/breakpoints.min.js new file mode 100644 index 0000000..32419cc --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/js/breakpoints.min.js @@ -0,0 +1,2 @@ +/* breakpoints.js v1.0 | @ajlkn | MIT licensed */ +var breakpoints=function(){"use strict";function e(e){t.init(e)}var t={list:null,media:{},events:[],init:function(e){t.list=e,window.addEventListener("resize",t.poll),window.addEventListener("orientationchange",t.poll),window.addEventListener("load",t.poll),window.addEventListener("fullscreenchange",t.poll)},active:function(e){var n,a,s,i,r,d,c;if(!(e in t.media)){if(">="==e.substr(0,2)?(a="gte",n=e.substr(2)):"<="==e.substr(0,2)?(a="lte",n=e.substr(2)):">"==e.substr(0,1)?(a="gt",n=e.substr(1)):"<"==e.substr(0,1)?(a="lt",n=e.substr(1)):"!"==e.substr(0,1)?(a="not",n=e.substr(1)):(a="eq",n=e),n&&n in t.list)if(i=t.list[n],Array.isArray(i)){if(r=parseInt(i[0]),d=parseInt(i[1]),isNaN(r)){if(isNaN(d))return;c=i[1].substr(String(d).length)}else c=i[0].substr(String(r).length);if(isNaN(r))switch(a){case"gte":s="screen";break;case"lte":s="screen and (max-width: "+d+c+")";break;case"gt":s="screen and (min-width: "+(d+1)+c+")";break;case"lt":s="screen and (max-width: -1px)";break;case"not":s="screen and (min-width: "+(d+1)+c+")";break;default:s="screen and (max-width: "+d+c+")"}else if(isNaN(d))switch(a){case"gte":s="screen and (min-width: "+r+c+")";break;case"lte":s="screen";break;case"gt":s="screen and (max-width: -1px)";break;case"lt":s="screen and (max-width: "+(r-1)+c+")";break;case"not":s="screen and (max-width: "+(r-1)+c+")";break;default:s="screen and (min-width: "+r+c+")"}else switch(a){case"gte":s="screen and (min-width: "+r+c+")";break;case"lte":s="screen and (max-width: "+d+c+")";break;case"gt":s="screen and (min-width: "+(d+1)+c+")";break;case"lt":s="screen and (max-width: "+(r-1)+c+")";break;case"not":s="screen and (max-width: "+(r-1)+c+"), screen and (min-width: "+(d+1)+c+")";break;default:s="screen and (min-width: "+r+c+") and (max-width: "+d+c+")"}}else s="("==i.charAt(0)?"screen and "+i:i;t.media[e]=!!s&&s}return t.media[e]!==!1&&window.matchMedia(t.media[e]).matches},on:function(e,n){t.events.push({query:e,handler:n,state:!1}),t.active(e)&&n()},poll:function(){var e,n;for(e=0;e+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0large', function() { + $sidebar.removeClass('inactive'); + }); + + // Hack: Workaround for Chrome/Android scrollbar position bug. + if (browser.os == 'android' + && browser.name == 'chrome') + $('') + .appendTo($head); + + // Toggle. + $('Toggle') + .appendTo($sidebar) + .on('click', function(event) { + + // Prevent default. + event.preventDefault(); + event.stopPropagation(); + + // Toggle. + $sidebar.toggleClass('inactive'); + + }); + + // Events. + + // Link clicks. + $sidebar.on('click', 'a', function(event) { + + // >large? Bail. + if (breakpoints.active('>large')) + return; + + // Vars. + var $a = $(this), + href = $a.attr('href'), + target = $a.attr('target'); + + // Prevent default. + event.preventDefault(); + event.stopPropagation(); + + // Check URL. + if (!href || href == '#' || href == '') + return; + + // Hide sidebar. + $sidebar.addClass('inactive'); + + // Redirect to href. + setTimeout(function() { + + if (target == '_blank') + window.open(href); + else + window.location.href = href; + + }, 500); + + }); + + // Prevent certain events inside the panel from bubbling. + $sidebar.on('click touchend touchstart touchmove', function(event) { + + // >large? Bail. + if (breakpoints.active('>large')) + return; + + // Prevent propagation. + event.stopPropagation(); + + }); + + // Hide panel on body click/tap. + $body.on('click touchend', function(event) { + + // >large? Bail. + if (breakpoints.active('>large')) + return; + + // Deactivate. + $sidebar.addClass('inactive'); + + }); + + // Scroll lock. + // Note: If you do anything to change the height of the sidebar's content, be sure to + // trigger 'resize.sidebar-lock' on $window so stuff doesn't get out of sync. + + $window.on('load.sidebar-lock', function() { + + var sh, wh, st; + + // Reset scroll position to 0 if it's 1. + if ($window.scrollTop() == 1) + $window.scrollTop(0); + + $window + .on('scroll.sidebar-lock', function() { + + var x, y; + + // <=large? Bail. + if (breakpoints.active('<=large')) { + + $sidebar_inner + .data('locked', 0) + .css('position', '') + .css('top', ''); + + return; + + } + + // Calculate positions. + x = Math.max(sh - wh, 0); + y = Math.max(0, $window.scrollTop() - x); + + // Lock/unlock. + if ($sidebar_inner.data('locked') == 1) { + + if (y <= 0) + $sidebar_inner + .data('locked', 0) + .css('position', '') + .css('top', ''); + else + $sidebar_inner + .css('top', -1 * x); + + } + else { + + if (y > 0) + $sidebar_inner + .data('locked', 1) + .css('position', 'fixed') + .css('top', -1 * x); + + } + + }) + .on('resize.sidebar-lock', function() { + + // Calculate heights. + wh = $window.height(); + sh = $sidebar_inner.outerHeight() + 30; + + // Trigger scroll. + $window.trigger('scroll.sidebar-lock'); + + }) + .trigger('resize.sidebar-lock'); + + }); + + // Menu. + var $menu = $('#menu'), + $menu_openers = $menu.children('ul').find('.opener'); + + // Openers. + $menu_openers.each(function() { + + var $this = $(this); + + $this.on('click', function(event) { + + // Prevent default. + event.preventDefault(); + + // Toggle. + $menu_openers.not($this).removeClass('active'); + $this.toggleClass('active'); + + // Trigger resize (sidebar lock). + $window.triggerHandler('resize.sidebar-lock'); + + }); + + }); + +})(jQuery); diff --git a/pythoncms/static/themes/front/editorial/assets/js/util.js b/pythoncms/static/themes/front/editorial/assets/js/util.js new file mode 100644 index 0000000..3633ca6 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/js/util.js @@ -0,0 +1,587 @@ +(function($) { + + /** + * Generate an indented list of links from a nav. Meant for use with panel(). + * @return {jQuery} jQuery object. + */ + $.fn.navList = function() { + + var $this = $(this); + $a = $this.find('a'), + b = []; + + $a.each(function() { + + var $this = $(this), + indent = Math.max(0, $this.parents('li').length - 1), + href = $this.attr('href'), + target = $this.attr('target'); + + b.push( + '' + + '' + + $this.text() + + '' + ); + + }); + + return b.join(''); + + }; + + /** + * Panel-ify an element. + * @param {object} userConfig User config. + * @return {jQuery} jQuery object. + */ + $.fn.panel = function(userConfig) { + + // No elements? + if (this.length == 0) + return $this; + + // Multiple elements? + if (this.length > 1) { + + for (var i=0; i < this.length; i++) + $(this[i]).panel(userConfig); + + return $this; + + } + + // Vars. + var $this = $(this), + $body = $('body'), + $window = $(window), + id = $this.attr('id'), + config; + + // Config. + config = $.extend({ + + // Delay. + delay: 0, + + // Hide panel on link click. + hideOnClick: false, + + // Hide panel on escape keypress. + hideOnEscape: false, + + // Hide panel on swipe. + hideOnSwipe: false, + + // Reset scroll position on hide. + resetScroll: false, + + // Reset forms on hide. + resetForms: false, + + // Side of viewport the panel will appear. + side: null, + + // Target element for "class". + target: $this, + + // Class to toggle. + visibleClass: 'visible' + + }, userConfig); + + // Expand "target" if it's not a jQuery object already. + if (typeof config.target != 'jQuery') + config.target = $(config.target); + + // Panel. + + // Methods. + $this._hide = function(event) { + + // Already hidden? Bail. + if (!config.target.hasClass(config.visibleClass)) + return; + + // If an event was provided, cancel it. + if (event) { + + event.preventDefault(); + event.stopPropagation(); + + } + + // Hide. + config.target.removeClass(config.visibleClass); + + // Post-hide stuff. + window.setTimeout(function() { + + // Reset scroll position. + if (config.resetScroll) + $this.scrollTop(0); + + // Reset forms. + if (config.resetForms) + $this.find('form').each(function() { + this.reset(); + }); + + }, config.delay); + + }; + + // Vendor fixes. + $this + .css('-ms-overflow-style', '-ms-autohiding-scrollbar') + .css('-webkit-overflow-scrolling', 'touch'); + + // Hide on click. + if (config.hideOnClick) { + + $this.find('a') + .css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)'); + + $this + .on('click', 'a', function(event) { + + var $a = $(this), + href = $a.attr('href'), + target = $a.attr('target'); + + if (!href || href == '#' || href == '' || href == '#' + id) + return; + + // Cancel original event. + event.preventDefault(); + event.stopPropagation(); + + // Hide panel. + $this._hide(); + + // Redirect to href. + window.setTimeout(function() { + + if (target == '_blank') + window.open(href); + else + window.location.href = href; + + }, config.delay + 10); + + }); + + } + + // Event: Touch stuff. + $this.on('touchstart', function(event) { + + $this.touchPosX = event.originalEvent.touches[0].pageX; + $this.touchPosY = event.originalEvent.touches[0].pageY; + + }) + + $this.on('touchmove', function(event) { + + if ($this.touchPosX === null + || $this.touchPosY === null) + return; + + var diffX = $this.touchPosX - event.originalEvent.touches[0].pageX, + diffY = $this.touchPosY - event.originalEvent.touches[0].pageY, + th = $this.outerHeight(), + ts = ($this.get(0).scrollHeight - $this.scrollTop()); + + // Hide on swipe? + if (config.hideOnSwipe) { + + var result = false, + boundary = 20, + delta = 50; + + switch (config.side) { + + case 'left': + result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta); + break; + + case 'right': + result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta)); + break; + + case 'top': + result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta); + break; + + case 'bottom': + result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta)); + break; + + default: + break; + + } + + if (result) { + + $this.touchPosX = null; + $this.touchPosY = null; + $this._hide(); + + return false; + + } + + } + + // Prevent vertical scrolling past the top or bottom. + if (($this.scrollTop() < 0 && diffY < 0) + || (ts > (th - 2) && ts < (th + 2) && diffY > 0)) { + + event.preventDefault(); + event.stopPropagation(); + + } + + }); + + // Event: Prevent certain events inside the panel from bubbling. + $this.on('click touchend touchstart touchmove', function(event) { + event.stopPropagation(); + }); + + // Event: Hide panel if a child anchor tag pointing to its ID is clicked. + $this.on('click', 'a[href="#' + id + '"]', function(event) { + + event.preventDefault(); + event.stopPropagation(); + + config.target.removeClass(config.visibleClass); + + }); + + // Body. + + // Event: Hide panel on body click/tap. + $body.on('click touchend', function(event) { + $this._hide(event); + }); + + // Event: Toggle. + $body.on('click', 'a[href="#' + id + '"]', function(event) { + + event.preventDefault(); + event.stopPropagation(); + + config.target.toggleClass(config.visibleClass); + + }); + + // Window. + + // Event: Hide on ESC. + if (config.hideOnEscape) + $window.on('keydown', function(event) { + + if (event.keyCode == 27) + $this._hide(event); + + }); + + return $this; + + }; + + /** + * Apply "placeholder" attribute polyfill to one or more forms. + * @return {jQuery} jQuery object. + */ + $.fn.placeholder = function() { + + // Browser natively supports placeholders? Bail. + if (typeof (document.createElement('input')).placeholder != 'undefined') + return $(this); + + // No elements? + if (this.length == 0) + return $this; + + // Multiple elements? + if (this.length > 1) { + + for (var i=0; i < this.length; i++) + $(this[i]).placeholder(); + + return $this; + + } + + // Vars. + var $this = $(this); + + // Text, TextArea. + $this.find('input[type=text],textarea') + .each(function() { + + var i = $(this); + + if (i.val() == '' + || i.val() == i.attr('placeholder')) + i + .addClass('polyfill-placeholder') + .val(i.attr('placeholder')); + + }) + .on('blur', function() { + + var i = $(this); + + if (i.attr('name').match(/-polyfill-field$/)) + return; + + if (i.val() == '') + i + .addClass('polyfill-placeholder') + .val(i.attr('placeholder')); + + }) + .on('focus', function() { + + var i = $(this); + + if (i.attr('name').match(/-polyfill-field$/)) + return; + + if (i.val() == i.attr('placeholder')) + i + .removeClass('polyfill-placeholder') + .val(''); + + }); + + // Password. + $this.find('input[type=password]') + .each(function() { + + var i = $(this); + var x = $( + $('
') + .append(i.clone()) + .remove() + .html() + .replace(/type="password"/i, 'type="text"') + .replace(/type=password/i, 'type=text') + ); + + if (i.attr('id') != '') + x.attr('id', i.attr('id') + '-polyfill-field'); + + if (i.attr('name') != '') + x.attr('name', i.attr('name') + '-polyfill-field'); + + x.addClass('polyfill-placeholder') + .val(x.attr('placeholder')).insertAfter(i); + + if (i.val() == '') + i.hide(); + else + x.hide(); + + i + .on('blur', function(event) { + + event.preventDefault(); + + var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]'); + + if (i.val() == '') { + + i.hide(); + x.show(); + + } + + }); + + x + .on('focus', function(event) { + + event.preventDefault(); + + var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']'); + + x.hide(); + + i + .show() + .focus(); + + }) + .on('keypress', function(event) { + + event.preventDefault(); + x.val(''); + + }); + + }); + + // Events. + $this + .on('submit', function() { + + $this.find('input[type=text],input[type=password],textarea') + .each(function(event) { + + var i = $(this); + + if (i.attr('name').match(/-polyfill-field$/)) + i.attr('name', ''); + + if (i.val() == i.attr('placeholder')) { + + i.removeClass('polyfill-placeholder'); + i.val(''); + + } + + }); + + }) + .on('reset', function(event) { + + event.preventDefault(); + + $this.find('select') + .val($('option:first').val()); + + $this.find('input,textarea') + .each(function() { + + var i = $(this), + x; + + i.removeClass('polyfill-placeholder'); + + switch (this.type) { + + case 'submit': + case 'reset': + break; + + case 'password': + i.val(i.attr('defaultValue')); + + x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]'); + + if (i.val() == '') { + i.hide(); + x.show(); + } + else { + i.show(); + x.hide(); + } + + break; + + case 'checkbox': + case 'radio': + i.attr('checked', i.attr('defaultValue')); + break; + + case 'text': + case 'textarea': + i.val(i.attr('defaultValue')); + + if (i.val() == '') { + i.addClass('polyfill-placeholder'); + i.val(i.attr('placeholder')); + } + + break; + + default: + i.val(i.attr('defaultValue')); + break; + + } + }); + + }); + + return $this; + + }; + + /** + * Moves elements to/from the first positions of their respective parents. + * @param {jQuery} $elements Elements (or selector) to move. + * @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations. + */ + $.prioritize = function($elements, condition) { + + var key = '__prioritize'; + + // Expand $elements if it's not already a jQuery object. + if (typeof $elements != 'jQuery') + $elements = $($elements); + + // Step through elements. + $elements.each(function() { + + var $e = $(this), $p, + $parent = $e.parent(); + + // No parent? Bail. + if ($parent.length == 0) + return; + + // Not moved? Move it. + if (!$e.data(key)) { + + // Condition is false? Bail. + if (!condition) + return; + + // Get placeholder (which will serve as our point of reference for when this element needs to move back). + $p = $e.prev(); + + // Couldn't find anything? Means this element's already at the top, so bail. + if ($p.length == 0) + return; + + // Move element to top of parent. + $e.prependTo($parent); + + // Mark element as moved. + $e.data(key, $p); + + } + + // Moved already? + else { + + // Condition is true? Bail. + if (condition) + return; + + $p = $e.data(key); + + // Move element back to its original location (using our placeholder). + $e.insertAfter($p); + + // Unmark element as moved. + $e.removeData(key); + + } + + }); + + }; + +})(jQuery); diff --git a/pythoncms/static/themes/front/editorial/assets/sass/base/_page.scss b/pythoncms/static/themes/front/editorial/assets/sass/base/_page.scss new file mode 100644 index 0000000..36fa1ba --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/base/_page.scss @@ -0,0 +1,48 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Basic */ + + // MSIE: Required for IEMobile. + @-ms-viewport { + width: device-width; + } + + // MSIE: Prevents scrollbar from overlapping content. + body { + -ms-overflow-style: scrollbar; + } + + // Ensures page width is always >=320px. + @include breakpoint('<=xsmall') { + html, body { + min-width: 320px; + } + } + + // Set box model to border-box. + // Based on css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice + html { + box-sizing: border-box; + } + + *, *:before, *:after { + box-sizing: inherit; + } + + body { + background: _palette(bg); + + // Stops initial animations until page loads or stops resizing. + &.is-preload, + &.is-resizing { + *, *:before, *:after { + @include vendor('animation', 'none !important'); + @include vendor('transition', 'none !important'); + } + } + + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/base/_reset.scss b/pythoncms/static/themes/front/editorial/assets/sass/base/_reset.scss new file mode 100644 index 0000000..84c5e8c --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/base/_reset.scss @@ -0,0 +1,76 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +// Reset. +// Based on meyerweb.com/eric/tools/css/reset (v2.0 | 20110126 | License: public domain) + + html, body, div, span, applet, object, + iframe, h1, h2, h3, h4, h5, h6, p, blockquote, + pre, a, abbr, acronym, address, big, cite, + code, del, dfn, em, img, ins, kbd, q, s, samp, + small, strike, strong, sub, sup, tt, var, b, + u, i, center, dl, dt, dd, ol, ul, li, fieldset, + form, label, legend, table, caption, tbody, + tfoot, thead, tr, th, td, article, aside, + canvas, details, embed, figure, figcaption, + footer, header, hgroup, menu, nav, output, ruby, + section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; + } + + article, aside, details, figcaption, figure, + footer, header, hgroup, menu, nav, section { + display: block; + } + + body { + line-height: 1; + } + + ol, ul { + list-style:none; + } + + blockquote, q { + quotes: none; + + &:before, + &:after { + content: ''; + content: none; + } + } + + table { + border-collapse: collapse; + border-spacing: 0; + } + + body { + -webkit-text-size-adjust: none; + } + + mark { + background-color: transparent; + color: inherit; + } + + input::-moz-focus-inner { + border: 0; + padding: 0; + } + + input, select, textarea { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/base/_typography.scss b/pythoncms/static/themes/front/editorial/assets/sass/base/_typography.scss new file mode 100644 index 0000000..479da11 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/base/_typography.scss @@ -0,0 +1,187 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Type */ + + body, input, select, textarea { + color: _palette(fg); + font-family: _font(family); + font-size: 13pt; + font-weight: _font(weight); + line-height: 1.65; + + @include breakpoint('<=xlarge') { + font-size: 11pt; + } + + @include breakpoint('<=large') { + font-size: 10pt; + } + + @include breakpoint('<=xxsmall') { + font-size: 9pt; + } + } + + a { + @include vendor('transition', ( + 'color #{_duration(transition)} ease-in-out', + 'border-bottom-color #{_duration(transition)} ease-in-out' + )); + border-bottom: dotted 1px; + color: _palette(accent); + text-decoration: none; + + &:hover { + border-bottom-color: _palette(accent); + color: _palette(accent) !important; + + strong { + color: inherit; + } + } + } + + strong, b { + color: _palette(fg-bold); + font-weight: _font(weight-bold); + } + + em, i { + font-style: italic; + } + + p { + margin: 0 0 _size(element-margin) 0; + } + + h1, h2, h3, h4, h5, h6 { + color: _palette(fg-bold); + font-family: _font(family-heading); + font-weight: _font(weight-heading); + line-height: 1.5; + margin: 0 0 (_size(element-margin) * 0.5) 0; + + a { + color: inherit; + text-decoration: none; + border-bottom: 0; + } + } + + h1 { + font-size: 4em; + margin: 0 0 (_size(element-margin) * 0.25) 0; + line-height: 1.3; + } + + h2 { + font-size: 1.75em; + } + + h3 { + font-size: 1.25em; + } + + h4 { + font-size: 1.1em; + } + + h5 { + font-size: 0.9em; + } + + h6 { + font-size: 0.7em; + } + + @include breakpoint('<=xlarge') { + h1 { + font-size: 3.5em; + } + } + + @include breakpoint('<=medium') { + h1 { + font-size: 3.25em; + } + } + + @include breakpoint('<=small') { + h1 { + font-size: 2em; + line-height: 1.4; + } + + h2 { + font-size: 1.5em; + } + } + + sub { + font-size: 0.8em; + position: relative; + top: 0.5em; + } + + sup { + font-size: 0.8em; + position: relative; + top: -0.5em; + } + + blockquote { + border-left: solid 3px _palette(border); + font-style: italic; + margin: 0 0 _size(element-margin) 0; + padding: (_size(element-margin) / 4) 0 (_size(element-margin) / 4) _size(element-margin); + } + + code { + background: _palette(border-bg); + border-radius: _size(border-radius); + border: solid 1px _palette(border); + font-family: _font(family-fixed); + font-size: 0.9em; + margin: 0 0.25em; + padding: 0.25em 0.65em; + } + + pre { + -webkit-overflow-scrolling: touch; + font-family: _font(family-fixed); + font-size: 0.9em; + margin: 0 0 _size(element-margin) 0; + + code { + display: block; + line-height: 1.75; + padding: 1em 1.5em; + overflow-x: auto; + } + } + + hr { + border: 0; + border-bottom: solid 1px _palette(border); + margin: _size(element-margin) 0; + + &.major { + margin: (_size(element-margin) * 1.5) 0; + } + } + + .align-left { + text-align: left; + } + + .align-center { + text-align: center; + } + + .align-right { + text-align: right; + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_actions.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_actions.scss new file mode 100644 index 0000000..f93de83 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_actions.scss @@ -0,0 +1,63 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Actions */ + + ul.actions { + @include vendor('display', 'flex'); + cursor: default; + list-style: none; + margin-left: (_size(element-margin) * -0.5); + padding-left: 0; + + li { + padding: 0 0 0 (_size(element-margin) * 0.5); + vertical-align: middle; + } + + &.special { + @include vendor('justify-content', 'center'); + width: 100%; + margin-left: 0; + + li { + &:first-child { + padding-left: 0; + } + } + } + + &.stacked { + @include vendor('flex-direction', 'column'); + margin-left: 0; + + li { + padding: (_size(element-margin) * 0.65) 0 0 0; + + &:first-child { + padding-top: 0; + } + } + } + + &.fit { + width: calc(100% + #{_size(element-margin) * 0.5}); + + li { + @include vendor('flex-grow', '1'); + @include vendor('flex-shrink', '1'); + width: 100%; + + > * { + width: 100%; + } + } + + &.stacked { + width: 100%; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_box.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_box.scss new file mode 100644 index 0000000..4b0dbc4 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_box.scss @@ -0,0 +1,26 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Box */ + + .box { + border-radius: _size(border-radius); + border: solid 1px _palette(border); + margin-bottom: _size(element-margin); + padding: 1.5em; + + > :last-child, + > :last-child > :last-child, + > :last-child > :last-child > :last-child { + margin-bottom: 0; + } + + &.alt { + border: 0; + border-radius: 0; + padding: 0; + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_button.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_button.scss new file mode 100644 index 0000000..818a53a --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_button.scss @@ -0,0 +1,85 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Button */ + + input[type="submit"], + input[type="reset"], + input[type="button"], + button, + .button { + @include vendor('appearance', 'none'); + @include vendor('transition', ( + 'background-color #{_duration(transition)} ease-in-out', + 'color #{_duration(transition)} ease-in-out' + )); + background-color: transparent; + border-radius: _size(border-radius); + border: 0; + box-shadow: inset 0 0 0 2px _palette(accent); + color: _palette(accent) !important; + cursor: pointer; + display: inline-block; + font-family: _font(family-heading); + font-size: 0.8em; + font-weight: _font(weight-heading); + height: 3.5em; + letter-spacing: _font(kerning-heading); + line-height: 3.5em; + padding: 0 2.25em; + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + + &:hover { + background-color: transparentize(_palette(accent), 0.95); + } + + &:active { + background-color: transparentize(_palette(accent), 0.85); + } + + &.icon { + &:before { + margin-right: 0.5em; + } + } + + &.fit { + width: 100%; + } + + &.small { + font-size: 0.6em; + } + + &.large { + font-size: 1em; + height: 3.65em; + line-height: 3.65em; + } + + &.primary { + background-color: _palette(accent); + box-shadow: none; + color: _palette(bg) !important; + + &:hover { + background-color: lighten(_palette(accent), 3); + } + + &:active { + background-color: darken(_palette(accent), 3); + } + } + + &.disabled, + &:disabled { + @include vendor('pointer-events', 'none'); + opacity: 0.25; + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_contact.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_contact.scss new file mode 100644 index 0000000..24ed48f --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_contact.scss @@ -0,0 +1,47 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Contact */ + + ul.contact { + list-style: none; + padding: 0; + + li { + @include icon; + border-top: solid 1px _palette(border); + margin: 1.5em 0 0 0; + padding: 1.5em 0 0 3em; + position: relative; + + &:before { + color: _palette(accent); + display: inline-block; + font-size: 1.5em; + height: 1.125em; + left: 0; + line-height: 1.125em; + position: absolute; + text-align: center; + top: (1.5em / 1.5); + width: 1.5em; + } + + &:first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; + + &:before { + top: 0; + } + } + + a { + color: inherit; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_features.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_features.scss new file mode 100644 index 0000000..bb5bfbe --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_features.scss @@ -0,0 +1,156 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Features */ + + .features { + $gutter: _size(gutter); + + @include vendor('display', 'flex'); + @include vendor('flex-wrap', 'wrap'); + margin: 0 0 _size(element-margin) ($gutter * -1); + width: calc(100% + #{$gutter}); + + article { + @include vendor('align-items', 'center'); + @include vendor('display', 'flex'); + margin: 0 0 $gutter $gutter; + position: relative; + width: calc(50% - #{$gutter}); + + &:nth-child(2n - 1) { + margin-right: ($gutter * 0.5); + } + + &:nth-child(2n) { + margin-left: ($gutter * 0.5); + } + + &:nth-last-child(1), + &:nth-last-child(2) { + margin-bottom: 0; + } + + .icon { + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '0'); + display: block; + height: 10em; + line-height: 10em; + margin: 0 _size(element-margin) 0 0; + text-align: center; + width: 10em; + + &:before { + color: _palette(accent); + font-size: 2.75rem; + position: relative; + top: 0.05em; + } + + &:after { + @include vendor('transform', 'rotate(45deg)'); + border-radius: 0.25rem; + border: solid 2px _palette(border); + content: ''; + display: block; + height: 7em; + left: 50%; + margin: -3.5em 0 0 -3.5em; + position: absolute; + top: 50%; + width: 7em; + } + } + + .content { + @include vendor('flex-grow', '1'); + @include vendor('flex-shrink', '1'); + width: 100%; + + > :last-child { + margin-bottom: 0; + } + } + } + + @include breakpoint('<=medium') { + margin: 0 0 _size(element-margin) 0; + width: 100%; + + article { + margin: 0 0 $gutter 0; + width: 100%; + + &:nth-child(2n - 1) { + margin-right: 0; + } + + &:nth-child(2n) { + margin-left: 0; + } + + &:nth-last-child(1), + &:nth-last-child(2) { + margin-bottom: $gutter; + } + + &:last-child { + margin-bottom: 0; + } + + .icon { + height: 8em; + line-height: 8em; + width: 8em; + + &:before { + font-size: 2.25rem; + } + + &:after { + height: 6em; + margin: -3em 0 0 -3em; + width: 6em; + } + } + } + } + + @include breakpoint('<=xsmall') { + article { + @include vendor('flex-direction', 'column'); + @include vendor('align-items', 'flex-start'); + + .icon { + height: 6em; + line-height: 6em; + margin: 0 0 (_size(element-margin) * 0.75) 0; + width: 6em; + + &:before { + font-size: 1.5rem; + } + + &:after { + height: 4em; + margin: -2em 0 0 -2em; + width: 4em; + } + } + } + } + + @include breakpoint('<=xsmall') { + article { + .icon { + &:before { + font-size: 1.25rem; + } + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_form.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_form.scss new file mode 100644 index 0000000..c154e6c --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_form.scss @@ -0,0 +1,179 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Form */ + + form { + margin: 0 0 _size(element-margin) 0; + } + + label { + color: _palette(fg-bold); + display: block; + font-size: 0.9em; + font-weight: _font(weight-bold); + margin: 0 0 (_size(element-margin) * 0.5) 0; + } + + input[type="text"], + input[type="password"], + input[type="email"], + input[type="tel"], + input[type="search"], + input[type="url"], + select, + textarea { + @include vendor('appearance', 'none'); + background: _palette(bg); + border-radius: _size(border-radius); + border: none; + border: solid 1px _palette(border); + color: inherit; + display: block; + outline: 0; + padding: 0 1em; + text-decoration: none; + width: 100%; + + &:invalid { + box-shadow: none; + } + + &:focus { + border-color: _palette(accent); + box-shadow: 0 0 0 1px _palette(accent); + } + } + + select { + background-image: svg-url(""); + background-size: 1.25em; + background-repeat: no-repeat; + background-position: calc(100% - 1em) center; + height: _size(element-height); + padding-right: _size(element-height); + text-overflow: ellipsis; + + option { + color: _palette(fg-bold); + background: _palette(bg); + } + + &:focus { + &::-ms-value { + background-color: transparent; + } + } + + &::-ms-expand { + display: none; + } + } + + input[type="text"], + input[type="password"], + input[type="email"], + input[type="tel"], + input[type="search"], + input[type="url"], + select { + height: _size(element-height); + } + + textarea { + padding: 0.75em 1em; + } + + input[type="checkbox"], + input[type="radio"], { + @include vendor('appearance', 'none'); + display: block; + float: left; + margin-right: -2em; + opacity: 0; + width: 1em; + z-index: -1; + + & + label { + @include icon(false, solid); + color: _palette(fg); + cursor: pointer; + display: inline-block; + font-size: 1em; + font-weight: _font(weight); + padding-left: (_size(element-height) * 0.6) + 0.75em; + padding-right: 0.75em; + position: relative; + + &:before { + background: _palette(bg); + border-radius: _size(border-radius); + border: solid 1px _palette(border); + content: ''; + display: inline-block; + font-size: 0.8em; + height: (_size(element-height) * 0.75); + left: 0; + line-height: (_size(element-height) * 0.75); + position: absolute; + text-align: center; + top: 0; + width: (_size(element-height) * 0.75); + } + } + + &:checked + label { + &:before { + background: _palette(fg-bold); + border-color: _palette(fg-bold); + color: _palette(bg); + content: '\f00c'; + } + } + + &:focus + label { + &:before { + border-color: _palette(accent); + box-shadow: 0 0 0 1px _palette(accent); + } + } + } + + input[type="checkbox"] { + & + label { + &:before { + border-radius: _size(border-radius); + } + } + } + + input[type="radio"] { + & + label { + &:before { + border-radius: 100%; + } + } + } + + ::-webkit-input-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } + + :-moz-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } + + ::-moz-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } + + :-ms-input-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_icon.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_icon.scss new file mode 100644 index 0000000..5f6e888 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_icon.scss @@ -0,0 +1,33 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Icon */ + + .icon { + @include icon; + border-bottom: none; + position: relative; + + > .label { + display: none; + } + + &:before { + line-height: inherit; + } + + &.solid { + &:before { + font-weight: 900; + } + } + + &.brands { + &:before { + font-family: 'Font Awesome 5 Brands'; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_icons.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_icons.scss new file mode 100644 index 0000000..0d0dba5 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_icons.scss @@ -0,0 +1,30 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Icons */ + + ul.icons { + cursor: default; + list-style: none; + padding-left: 0; + + li { + display: inline-block; + padding: 0 1em 0 0; + + &:last-child { + padding-right: 0; + } + + .icon { + color: inherit; + + &:before { + font-size: 1.25em; + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_image.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_image.scss new file mode 100644 index 0000000..5014b41 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_image.scss @@ -0,0 +1,74 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Image */ + + .image { + border-radius: _size(border-radius); + border: 0; + display: inline-block; + position: relative; + + img { + border-radius: _size(border-radius); + display: block; + } + + &.left, + &.right { + max-width: 40%; + + img { + width: 100%; + } + } + + &.left { + float: left; + padding: 0 1.5em 1em 0; + top: 0.25em; + } + + &.right { + float: right; + padding: 0 0 1em 1.5em; + top: 0.25em; + } + + &.fit { + display: block; + margin: 0 0 _size(element-margin) 0; + width: 100%; + + img { + width: 100%; + } + } + + &.main { + display: block; + margin: 0 0 (_size(element-margin) * 1.5) 0; + width: 100%; + + img { + width: 100%; + } + } + } + + a.image { + overflow: hidden; + + img { + @include vendor('transition', 'transform #{_duration(transition)} ease'); + } + + &:hover { + img { + @include vendor('transform', 'scale(1.075)'); + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_list.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_list.scss new file mode 100644 index 0000000..a7a1e57 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_list.scss @@ -0,0 +1,56 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* List */ + + ol { + list-style: decimal; + margin: 0 0 _size(element-margin) 0; + padding-left: 1.25em; + + li { + padding-left: 0.25em; + } + } + + ul { + list-style: disc; + margin: 0 0 _size(element-margin) 0; + padding-left: 1em; + + li { + padding-left: 0.5em; + } + + &.alt { + list-style: none; + padding-left: 0; + + li { + border-top: solid 1px _palette(border); + padding: 0.5em 0; + + &:first-child { + border-top: 0; + padding-top: 0; + } + } + } + } + + dl { + margin: 0 0 _size(element-margin) 0; + + dt { + display: block; + font-weight: _font(weight-bold); + margin: 0 0 (_size(element-margin) * 0.5) 0; + } + + dd { + margin-left: _size(element-margin); + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_mini-posts.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_mini-posts.scss new file mode 100644 index 0000000..e407457 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_mini-posts.scss @@ -0,0 +1,31 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Mini Posts */ + + .mini-posts { + article { + border-top: solid 1px _palette(border); + margin-top: _size(element-margin); + padding-top: _size(element-margin); + + .image { + display: block; + margin: 0 0 (_size(element-margin) * 0.75) 0; + + img { + display: block; + width: 100%; + } + } + + &:first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_pagination.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_pagination.scss new file mode 100644 index 0000000..5a8849a --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_pagination.scss @@ -0,0 +1,70 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Pagination */ + + ul.pagination { + cursor: default; + list-style: none; + padding-left: 0; + + li { + display: inline-block; + padding-left: 0; + vertical-align: middle; + + > .page { + @include vendor('transition', ( + 'background-color #{_duration(transition)} ease-in-out', + 'color #{_duration(transition)} ease-in-out' + )); + border-bottom: 0; + border-radius: _size(border-radius); + display: inline-block; + font-size: 0.8em; + font-weight: _font(weight-bold); + height: 2em; + line-height: 2em; + margin: 0 0.125em; + min-width: 2em; + padding: 0 0.5em; + text-align: center; + + &.active { + background-color: _palette(accent); + color: _palette(bg) !important; + + &:hover { + background-color: lighten(_palette(accent), 3); + } + + &:active { + background-color: darken(_palette(accent), 3); + } + } + } + + &:first-child { + padding-right: 0.75em; + } + + &:last-child { + padding-left: 0.75em; + } + } + + @include breakpoint('<=xsmall') { + li { + &:nth-child(n+2):nth-last-child(n+2) { + display: none; + } + + &:first-child { + padding-right: 0; + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_posts.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_posts.scss new file mode 100644 index 0000000..8c23d42 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_posts.scss @@ -0,0 +1,179 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Posts */ + + .posts { + $gutter: (_size(gutter) * 2); + + @include vendor('display', 'flex'); + @include vendor('flex-wrap', 'wrap'); + margin: 0 0 _size(element-margin) ($gutter * -1); + width: calc(100% + #{$gutter}); + + article { + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '1'); + margin: 0 0 $gutter $gutter; + position: relative; + width: calc(#{(100% / 3)} - #{$gutter}); + + &:before { + background: _palette(border); + content: ''; + display: block; + height: calc(100% + #{$gutter}); + left: ($gutter * -0.5); + position: absolute; + top: 0; + width: 1px; + } + + &:after { + background: _palette(border); + bottom: ($gutter * -0.5); + content: ''; + display: block; + height: 1px; + position: absolute; + right: 0; + width: calc(100% + #{$gutter}); + } + + > :last-child { + margin-bottom: 0; + } + + .image { + display: block; + margin: 0 0 _size(element-margin) 0; + + img { + display: block; + width: 100%; + } + } + } + + @include breakpoint('xlarge-to-max') { + article { + &:nth-child(3n + 1) { + &:before { + display: none; + } + + &:after { + width: 100%; + } + } + + &:nth-last-child(1), + &:nth-last-child(2), + &:nth-last-child(3) { + margin-bottom: 0; + + &:before { + height: 100%; + } + + &:after { + display: none; + } + } + } + } + + @include breakpoint('<=xlarge') { + article { + width: calc(50% - #{$gutter}); + + &:nth-last-child(3) { + margin-bottom: $gutter; + } + } + } + + @include breakpoint('small-to-xlarge') { + article { + &:nth-child(2n + 1) { + &:before { + display: none; + } + + &:after { + width: 100%; + } + } + + &:nth-last-child(1), + &:nth-last-child(2) { + margin-bottom: 0; + + &:before { + height: 100%; + } + + &:after { + display: none; + } + } + } + } + + @include breakpoint('<=small') { + $gutter: _size(gutter) * 1.5; + + margin: 0 0 _size(element-margin) ($gutter * -1); + width: calc(100% + #{$gutter}); + + article { + margin: 0 0 $gutter $gutter; + width: calc(50% - #{$gutter}); + + &:before { + height: calc(100% + #{$gutter}); + left: ($gutter * -0.5); + } + + &:after { + bottom: ($gutter * -0.5); + width: calc(100% + #{$gutter}); + } + + &:nth-last-child(3) { + margin-bottom: $gutter; + } + } + } + + @include breakpoint('<=xsmall') { + $gutter: _size(gutter) * 1.5; + + margin: 0 0 _size(element-margin) 0; + width: 100%; + + article { + margin: 0 0 $gutter 0; + width: 100%; + + &:before { + display: none; + } + + &:after { + width: 100%; + } + + &:last-child { + margin-bottom: 0; + + &:after { + display: none; + } + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_row.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_row.scss new file mode 100644 index 0000000..9370999 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_row.scss @@ -0,0 +1,31 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Row */ + + .row { + @include html-grid(1.5em); + + @include breakpoint('<=xlarge') { + @include html-grid(1.5em, 'xlarge'); + } + + @include breakpoint('<=large') { + @include html-grid(1.5em, 'large'); + } + + @include breakpoint('<=medium') { + @include html-grid(1.5em, 'medium'); + } + + @include breakpoint('<=small') { + @include html-grid(1.5em, 'small'); + } + + @include breakpoint('<=xsmall') { + @include html-grid(1.5em, 'xsmall'); + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_section.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_section.scss new file mode 100644 index 0000000..bebcdb1 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_section.scss @@ -0,0 +1,39 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Section/Article */ + + section, article { + &.special { + text-align: center; + } + } + + header { + p { + font-family: _font(family-heading); + font-size: 1em; + font-weight: _font(weight-heading-alt); + letter-spacing: _font(kerning-heading); + margin-top: -0.5em; + text-transform: uppercase; + } + + &.major { + > :last-child { + border-bottom: solid 3px _palette(accent); + display: inline-block; + margin: 0 0 _size(element-margin) 0; + padding: 0 0.75em 0.5em 0; + } + } + + &.main { + > :last-child { + margin: 0 0 (_size(element-margin) * 0.5) 0; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/components/_table.scss b/pythoncms/static/themes/front/editorial/assets/sass/components/_table.scss new file mode 100644 index 0000000..ee3c932 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/components/_table.scss @@ -0,0 +1,81 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Table */ + + .table-wrapper { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + } + + table { + margin: 0 0 _size(element-margin) 0; + width: 100%; + + tbody { + tr { + border: solid 1px _palette(border); + border-left: 0; + border-right: 0; + + &:nth-child(2n + 1) { + background-color: _palette(border-bg); + } + } + } + + td { + padding: 0.75em 0.75em; + } + + th { + color: _palette(fg-bold); + font-size: 0.9em; + font-weight: _font(weight-bold); + padding: 0 0.75em 0.75em 0.75em; + text-align: left; + } + + thead { + border-bottom: solid 2px _palette(border); + } + + tfoot { + border-top: solid 2px _palette(border); + } + + &.alt { + border-collapse: separate; + + tbody { + tr { + td { + border: solid 1px _palette(border); + border-left-width: 0; + border-top-width: 0; + + &:first-child { + border-left-width: 1px; + } + } + + &:first-child { + td { + border-top-width: 1px; + } + } + } + } + + thead { + border-bottom: 0; + } + + tfoot { + border-top: 0; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_banner.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_banner.scss new file mode 100644 index 0000000..886c60c --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_banner.scss @@ -0,0 +1,75 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Banner */ + + #banner { + @include padding(6em, 0); + @include vendor('display', 'flex'); + + h1 { + margin-top: -0.125em; + } + + .content { + @include vendor('flex-grow', '1'); + @include vendor('flex-shrink', '1'); + width: 50%; + } + + .image { + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '0'); + display: block; + margin: 0 0 _size(element-margin) (_size(element-margin) * 2); + width: 50%; + + img { + height: 100%; + -moz-object-fit: cover; + -webkit-object-fit: cover; + -ms-object-fit: cover; + object-fit: cover; + -moz-object-position: center; + -webkit-object-position: center; + -ms-object-position: center; + object-position: center; + width: 100%; + } + } + + @include orientation(portrait) { + @include vendor('flex-direction', 'column-reverse'); + + h1 { + br { + display: none; + } + } + + .content { + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '0'); + width: 100%; + } + + .image { + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '0'); + margin: 0 0 (_size(element-margin) * 2) 0; + height: 25em; + max-height: 50vh; + min-height: 18em; + width: 100%; + } + + @include breakpoint('<=xsmall') { + .image { + max-height: 35vh; + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_footer.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_footer.scss new file mode 100644 index 0000000..26c8f46 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_footer.scss @@ -0,0 +1,18 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Footer */ + + #footer { + .copyright { + color: _palette(fg-light); + font-size: 0.9em; + + a { + color: inherit; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_header.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_header.scss new file mode 100644 index 0000000..8f5d502 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_header.scss @@ -0,0 +1,51 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Header */ + + #header { + @include vendor('display', 'flex'); + border-bottom: solid 5px _palette(accent); + padding: 6em 0 1em 0; + position: relative; + + > * { + @include vendor('flex', '1'); + margin-bottom: 0; + } + + .logo { + border-bottom: 0; + color: inherit; + font-family: _font(family-heading); + font-size: 1.125em; + } + + .icons { + text-align: right; + } + + @include breakpoint('<=xlarge') { + padding-top: 5em; + } + + @include breakpoint('<=small') { + padding-top: 6.5em; + + .logo { + font-size: 1.25em; + margin: 0; + } + + .icons { + height: (6.25em / 1.25); + line-height: (6.25em / 1.25); + position: absolute; + right: (-0.625em / 1.25); + top: 0; + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_main.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_main.scss new file mode 100644 index 0000000..68cebd7 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_main.scss @@ -0,0 +1,58 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Main */ + + #main { + @include vendor('flex-grow', '1'); + @include vendor('flex-shrink', '1'); + width: 100%; + + > .inner { + @include padding(0, 6em); + margin: 0 auto; + max-width: 110em; + + > section { + @include padding(6em, 0); + border-top: solid 2px _palette(border); + + &:first-of-type { + border-top: 0 !important; + } + } + } + + @include breakpoint('<=xlarge') { + > .inner { + @include padding(0, 5em); + + > section { + @include padding(5em, 0); + } + } + } + + @include breakpoint('<=large') { + > .inner { + @include padding(0, 4em); + + > section { + @include padding(4em, 0); + } + } + } + + @include breakpoint('<=small') { + > .inner { + @include padding(0, 2em); + + > section { + @include padding(3em, 0); + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_menu.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_menu.scss new file mode 100644 index 0000000..b345bea --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_menu.scss @@ -0,0 +1,98 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Menu */ + + #menu { + ul { + @include vendor('user-select', 'none'); + color: _palette(fg-bold); + font-family: _font(family-heading); + font-weight: _font(weight-heading-alt); + letter-spacing: _font(kerning-heading); + list-style: none; + margin-bottom: 0; + padding: 0; + text-transform: uppercase; + + a, span { + border-bottom: 0; + color: inherit; + cursor: pointer; + display: block; + font-size: 0.9em; + padding: 0.625em 0; + + &:hover { + color: _palette(accent); + } + + &.opener { + @include vendor('transition', 'color #{_duration(transition)} ease-in-out'); + @include icon(false, solid); + -webkit-tap-highlight-color: rgba(255,255,255,0); + position: relative; + + &:before { + @include vendor('transition', ( + 'color #{_duration(transition)} ease-in-out', + 'transform #{_duration(transition)} ease-in-out' + )); + color: _palette(fg-light); + content: '\f078'; + position: absolute; + right: 0; + } + + &:hover { + &:before { + color: _palette(accent); + } + } + + &.active { + & + ul { + display: block; + } + + &:before { + @include vendor('transform', 'rotate(-180deg)'); + } + } + } + } + } + + > ul { + > li { + border-top: solid 1px _palette(border); + margin: 0.5em 0 0 0; + padding: 0.5em 0 0 0; + + > ul { + color: _palette(fg-light); + display: none; + margin: 0.5em 0 1.5em 0; + padding-left: 1em; + + a, span { + font-size: 0.8em; + } + + > li { + margin: 0.125em 0 0 0; + padding: 0.125em 0 0 0; + } + } + + &:first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_sidebar.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_sidebar.scss new file mode 100644 index 0000000..c2549e7 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_sidebar.scss @@ -0,0 +1,223 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Sidebar */ + + #search { + form { + @include icon(false, solid); + position: relative; + + &:before { + @include vendor('transform', 'scaleX(-1)'); + color: _palette(fg); + content: '\f002'; + cursor: default; + display: block; + font-size: 1.5em; + height: _size(element-height) / 1.375; + line-height: _size(element-height) / 1.375; + opacity: 0.325; + position: absolute; + right: 0; + text-align: center; + top: 0; + width: _size(element-height) / 1.375; + } + + input[type="text"] { + padding-right: _size(element-height); + } + } + } + + #sidebar { + $pad: 2em / 0.9; + + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '0'); + @include vendor('transition', ( + 'margin-left 0.5s ease', + 'box-shadow 0.5s ease' + )); + background-color: _palette(bg-alt); + font-size: 0.9em; + position: relative; + width: _size(sidebar-width); + + h2 { + font-size: (1.25em / 0.9); + } + + > .inner { + @include padding($pad, $pad, (0, 0, $pad, 0)); + position: relative; + width: _size(sidebar-width); + + > * { + border-bottom: solid 2px _palette(border); + margin: 0 0 (_size(element-margin) * 1.75) 0; + padding: 0 0 (_size(element-margin) * 1.75) 0; + + > :last-child { + margin-bottom: 0; + } + + &:last-child { + border-bottom: 0; + margin-bottom: 0; + padding-bottom: 0; + } + } + + > .alt { + background-color: darken(_palette(bg-alt), 2); + border-bottom: 0; + margin: ($pad * -1) 0 ($pad * 2) ($pad * -1); + padding: $pad; + width: calc(100% + #{$pad * 2}); + } + } + + .toggle { + @include icon(false, solid); + @include vendor('transition', 'left 0.5s ease'); + -webkit-tap-highlight-color: rgba(255,255,255,0); + border: 0; + display: block; + height: 7.5em; + left: _size(sidebar-width); + line-height: 7.5em; + outline: 0; + overflow: hidden; + position: absolute; + text-align: center; + text-indent: -15em; + white-space: nowrap; + top: 0; + width: 6em; + z-index: _misc(z-index-base); + + &:before { + content: '\f0c9'; + font-size: 2rem; + height: inherit; + left: 0; + line-height: inherit; + position: absolute; + text-indent: 0; + top: 0; + width: inherit; + } + } + + &.inactive { + margin-left: (_size(sidebar-width) * -1); + } + + @include breakpoint('<=xlarge') { + $pad: 1.5em / 0.9; + + width: _size(sidebar-width-alt); + + > .inner { + @include padding($pad, $pad, (0, 0, $pad, 0)); + width: _size(sidebar-width-alt); + + > .alt { + margin: ($pad * -1) 0 ($pad * 2) ($pad * -1); + padding: $pad; + width: calc(100% + #{$pad * 2}); + } + } + + .toggle { + height: 6.25em; + left: _size(sidebar-width-alt); + line-height: 6.25em; + text-indent: 5em; + width: 5em; + + &:before { + font-size: 1.5rem; + } + } + + &.inactive { + margin-left: (_size(sidebar-width-alt) * -1); + } + } + + @include breakpoint('<=large') { + box-shadow: 0 0 5em 0 rgba(0, 0, 0, 0.175); + height: 100%; + left: 0; + position: fixed; + top: 0; + z-index: _misc(z-index-base); + + &.inactive { + box-shadow: none; + } + + > .inner { + -webkit-overflow-scrolling: touch; + height: 100%; + left: 0; + overflow-x: hidden; + overflow-y: auto; + position: absolute; + top: 0; + + &:after { + content: ''; + display: block; + height: 4em; + width: 100%; + } + } + + .toggle { + text-indent: 6em; + width: 6em; + + &:before { + font-size: 1.5rem; + margin-left: (-0.875em / 2); + } + } + + body.is-preload & { + display: none; + } + } + + @include breakpoint('<=small') { + .toggle { + text-indent: 7.25em; + width: 7.25em; + + &:before { + color: _palette(fg); + margin-left: (-0.125em / 2); + margin-top: (-0.5em / 2); + font-size: 1.1rem; + z-index: 1; + } + + &:after { + background: transparentize(lighten(_palette(fg), 35), 0.25); + border-radius: _size(border-radius); + content: ''; + height: 3.5em; + left: 1em; + position: absolute; + top: 1em; + width: 5em; + } + } + } + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/layout/_wrapper.scss b/pythoncms/static/themes/front/editorial/assets/sass/layout/_wrapper.scss new file mode 100644 index 0000000..67062ca --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/layout/_wrapper.scss @@ -0,0 +1,13 @@ +/// +/// Editorial by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Wrapper */ + + #wrapper { + @include vendor('display', 'flex'); + @include vendor('flex-direction', 'row-reverse'); + min-height: 100vh; + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/libs/_breakpoints.scss b/pythoncms/static/themes/front/editorial/assets/sass/libs/_breakpoints.scss new file mode 100644 index 0000000..3769328 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/libs/_breakpoints.scss @@ -0,0 +1,223 @@ +// breakpoints.scss v1.0 | @ajlkn | MIT licensed */ + +// Vars. + + /// Breakpoints. + /// @var {list} + $breakpoints: () !global; + +// Mixins. + + /// Sets breakpoints. + /// @param {map} $x Breakpoints. + @mixin breakpoints($x: ()) { + $breakpoints: $x !global; + } + + /// Wraps @content in a @media block targeting a specific orientation. + /// @param {string} $orientation Orientation. + @mixin orientation($orientation) { + @media screen and (orientation: #{$orientation}) { + @content; + } + } + + /// Wraps @content in a @media block using a given query. + /// @param {string} $query Query. + @mixin breakpoint($query: null) { + + $breakpoint: null; + $op: null; + $media: null; + + // Determine operator, breakpoint. + + // Greater than or equal. + @if (str-slice($query, 0, 2) == '>=') { + + $op: 'gte'; + $breakpoint: str-slice($query, 3); + + } + + // Less than or equal. + @elseif (str-slice($query, 0, 2) == '<=') { + + $op: 'lte'; + $breakpoint: str-slice($query, 3); + + } + + // Greater than. + @elseif (str-slice($query, 0, 1) == '>') { + + $op: 'gt'; + $breakpoint: str-slice($query, 2); + + } + + // Less than. + @elseif (str-slice($query, 0, 1) == '<') { + + $op: 'lt'; + $breakpoint: str-slice($query, 2); + + } + + // Not. + @elseif (str-slice($query, 0, 1) == '!') { + + $op: 'not'; + $breakpoint: str-slice($query, 2); + + } + + // Equal. + @else { + + $op: 'eq'; + $breakpoint: $query; + + } + + // Build media. + @if ($breakpoint and map-has-key($breakpoints, $breakpoint)) { + + $a: map-get($breakpoints, $breakpoint); + + // Range. + @if (type-of($a) == 'list') { + + $x: nth($a, 1); + $y: nth($a, 2); + + // Max only. + @if ($x == null) { + + // Greater than or equal (>= 0 / anything) + @if ($op == 'gte') { + $media: 'screen'; + } + + // Less than or equal (<= y) + @elseif ($op == 'lte') { + $media: 'screen and (max-width: ' + $y + ')'; + } + + // Greater than (> y) + @elseif ($op == 'gt') { + $media: 'screen and (min-width: ' + ($y + 1) + ')'; + } + + // Less than (< 0 / invalid) + @elseif ($op == 'lt') { + $media: 'screen and (max-width: -1px)'; + } + + // Not (> y) + @elseif ($op == 'not') { + $media: 'screen and (min-width: ' + ($y + 1) + ')'; + } + + // Equal (<= y) + @else { + $media: 'screen and (max-width: ' + $y + ')'; + } + + } + + // Min only. + @else if ($y == null) { + + // Greater than or equal (>= x) + @if ($op == 'gte') { + $media: 'screen and (min-width: ' + $x + ')'; + } + + // Less than or equal (<= inf / anything) + @elseif ($op == 'lte') { + $media: 'screen'; + } + + // Greater than (> inf / invalid) + @elseif ($op == 'gt') { + $media: 'screen and (max-width: -1px)'; + } + + // Less than (< x) + @elseif ($op == 'lt') { + $media: 'screen and (max-width: ' + ($x - 1) + ')'; + } + + // Not (< x) + @elseif ($op == 'not') { + $media: 'screen and (max-width: ' + ($x - 1) + ')'; + } + + // Equal (>= x) + @else { + $media: 'screen and (min-width: ' + $x + ')'; + } + + } + + // Min and max. + @else { + + // Greater than or equal (>= x) + @if ($op == 'gte') { + $media: 'screen and (min-width: ' + $x + ')'; + } + + // Less than or equal (<= y) + @elseif ($op == 'lte') { + $media: 'screen and (max-width: ' + $y + ')'; + } + + // Greater than (> y) + @elseif ($op == 'gt') { + $media: 'screen and (min-width: ' + ($y + 1) + ')'; + } + + // Less than (< x) + @elseif ($op == 'lt') { + $media: 'screen and (max-width: ' + ($x - 1) + ')'; + } + + // Not (< x and > y) + @elseif ($op == 'not') { + $media: 'screen and (max-width: ' + ($x - 1) + '), screen and (min-width: ' + ($y + 1) + ')'; + } + + // Equal (>= x and <= y) + @else { + $media: 'screen and (min-width: ' + $x + ') and (max-width: ' + $y + ')'; + } + + } + + } + + // String. + @else { + + // Missing a media type? Prefix with "screen". + @if (str-slice($a, 0, 1) == '(') { + $media: 'screen and ' + $a; + } + + // Otherwise, use as-is. + @else { + $media: $a; + } + + } + + } + + // Output. + @media #{$media} { + @content; + } + + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/libs/_functions.scss b/pythoncms/static/themes/front/editorial/assets/sass/libs/_functions.scss new file mode 100644 index 0000000..ec6a29f --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/libs/_functions.scss @@ -0,0 +1,90 @@ +/// Removes a specific item from a list. +/// @author Hugo Giraudel +/// @param {list} $list List. +/// @param {integer} $index Index. +/// @return {list} Updated list. +@function remove-nth($list, $index) { + + $result: null; + + @if type-of($index) != number { + @warn "$index: #{quote($index)} is not a number for `remove-nth`."; + } + @else if $index == 0 { + @warn "List index 0 must be a non-zero integer for `remove-nth`."; + } + @else if abs($index) > length($list) { + @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`."; + } + @else { + + $result: (); + $index: if($index < 0, length($list) + $index + 1, $index); + + @for $i from 1 through length($list) { + + @if $i != $index { + $result: append($result, nth($list, $i)); + } + + } + + } + + @return $result; + +} + +/// Gets a value from a map. +/// @author Hugo Giraudel +/// @param {map} $map Map. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function val($map, $keys...) { + + @if nth($keys, 1) == null { + $keys: remove-nth($keys, 1); + } + + @each $key in $keys { + $map: map-get($map, $key); + } + + @return $map; + +} + +/// Gets a duration value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _duration($keys...) { + @return val($duration, $keys...); +} + +/// Gets a font value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _font($keys...) { + @return val($font, $keys...); +} + +/// Gets a misc value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _misc($keys...) { + @return val($misc, $keys...); +} + +/// Gets a palette value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _palette($keys...) { + @return val($palette, $keys...); +} + +/// Gets a size value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _size($keys...) { + @return val($size, $keys...); +} diff --git a/pythoncms/static/themes/front/editorial/assets/sass/libs/_html-grid.scss b/pythoncms/static/themes/front/editorial/assets/sass/libs/_html-grid.scss new file mode 100644 index 0000000..fbf0ac9 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/libs/_html-grid.scss @@ -0,0 +1,149 @@ +// html-grid.scss v1.0 | @ajlkn | MIT licensed */ + +// Mixins. + + /// Initializes the current element as an HTML grid. + /// @param {mixed} $gutters Gutters (either a single number to set both column/row gutters, or a list to set them individually). + /// @param {mixed} $suffix Column class suffix (optional; either a single suffix or a list). + @mixin html-grid($gutters: 1.5em, $suffix: '') { + + // Initialize. + $cols: 12; + $multipliers: 0, 0.25, 0.5, 1, 1.50, 2.00; + $unit: 100% / $cols; + + // Suffixes. + $suffixes: null; + + @if (type-of($suffix) == 'list') { + $suffixes: $suffix; + } + @else { + $suffixes: ($suffix); + } + + // Gutters. + $guttersCols: null; + $guttersRows: null; + + @if (type-of($gutters) == 'list') { + + $guttersCols: nth($gutters, 1); + $guttersRows: nth($gutters, 2); + + } + @else { + + $guttersCols: $gutters; + $guttersRows: 0; + + } + + // Row. + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + + // Columns. + > * { + box-sizing: border-box; + } + + // Gutters. + &.gtr-uniform { + > * { + > :last-child { + margin-bottom: 0; + } + } + } + + // Alignment. + &.aln-left { + justify-content: flex-start; + } + + &.aln-center { + justify-content: center; + } + + &.aln-right { + justify-content: flex-end; + } + + &.aln-top { + align-items: flex-start; + } + + &.aln-middle { + align-items: center; + } + + &.aln-bottom { + align-items: flex-end; + } + + // Step through suffixes. + @each $suffix in $suffixes { + + // Suffix. + @if ($suffix != '') { + $suffix: '-' + $suffix; + } + @else { + $suffix: ''; + } + + // Row. + + // Important. + > .imp#{$suffix} { + order: -1; + } + + // Columns, offsets. + @for $i from 1 through $cols { + > .col-#{$i}#{$suffix} { + width: $unit * $i; + } + + > .off-#{$i}#{$suffix} { + margin-left: $unit * $i; + } + } + + // Step through multipliers. + @each $multiplier in $multipliers { + + // Gutters. + $class: null; + + @if ($multiplier != 1) { + $class: '.gtr-' + ($multiplier * 100); + } + + &#{$class} { + margin-top: ($guttersRows * $multiplier * -1); + margin-left: ($guttersCols * $multiplier * -1); + + > * { + padding: ($guttersRows * $multiplier) 0 0 ($guttersCols * $multiplier); + } + + // Uniform. + &.gtr-uniform { + margin-top: $guttersCols * $multiplier * -1; + + > * { + padding-top: $guttersCols * $multiplier; + } + } + + } + + } + + } + + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/libs/_mixins.scss b/pythoncms/static/themes/front/editorial/assets/sass/libs/_mixins.scss new file mode 100644 index 0000000..612837d --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/libs/_mixins.scss @@ -0,0 +1,78 @@ +/// Makes an element's :before pseudoelement a FontAwesome icon. +/// @param {string} $content Optional content value to use. +/// @param {string} $category Optional category to use. +/// @param {string} $where Optional pseudoelement to target (before or after). +@mixin icon($content: false, $category: regular, $where: before) { + + text-decoration: none; + + &:#{$where} { + + @if $content { + content: $content; + } + + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + + @if ($category == brands) { + font-family: 'Font Awesome 5 Brands'; + } + @elseif ($category == solid) { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; + } + @else { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; + } + + } + +} + +/// Applies padding to an element, taking the current element-margin value into account. +/// @param {mixed} $tb Top/bottom padding. +/// @param {mixed} $lr Left/right padding. +/// @param {list} $pad Optional extra padding (in the following order top, right, bottom, left) +/// @param {bool} $important If true, adds !important. +@mixin padding($tb, $lr, $pad: (0,0,0,0), $important: null) { + + @if $important { + $important: '!important'; + } + + $x: 0.1em; + + @if unit(_size(element-margin)) == 'rem' { + $x: 0.1rem; + } + + padding: ($tb + nth($pad,1)) ($lr + nth($pad,2)) max($x, $tb - _size(element-margin) + nth($pad,3)) ($lr + nth($pad,4)) #{$important}; + +} + +/// Encodes a SVG data URL so IE doesn't choke (via codepen.io/jakob-e/pen/YXXBrp). +/// @param {string} $svg SVG data URL. +/// @return {string} Encoded SVG data URL. +@function svg-url($svg) { + + $svg: str-replace($svg, '"', '\''); + $svg: str-replace($svg, '%', '%25'); + $svg: str-replace($svg, '<', '%3C'); + $svg: str-replace($svg, '>', '%3E'); + $svg: str-replace($svg, '&', '%26'); + $svg: str-replace($svg, '#', '%23'); + $svg: str-replace($svg, '{', '%7B'); + $svg: str-replace($svg, '}', '%7D'); + $svg: str-replace($svg, ';', '%3B'); + + @return url("data:image/svg+xml;charset=utf8,#{$svg}"); + +} diff --git a/pythoncms/static/themes/front/editorial/assets/sass/libs/_vars.scss b/pythoncms/static/themes/front/editorial/assets/sass/libs/_vars.scss new file mode 100644 index 0000000..2559dfc --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/libs/_vars.scss @@ -0,0 +1,44 @@ +// Misc. + $misc: ( + z-index-base: 10000 + ); + +// Duration. + $duration: ( + nav: 0.5s, + transition: 0.2s + ); + +// Size. + $size: ( + border-radius: 0.375em, + element-height: 2.75em, + element-margin: 2em, + sidebar-width: 26em, + sidebar-width-alt: 24em, + gutter: 3em + ); + +// Font. + $font: ( + family: ('Open Sans', sans-serif), + family-heading: ('Roboto Slab', serif), + family-fixed: ('Courier New', monospace), + weight: 400, + weight-bold: 600, + weight-heading: 700, + weight-heading-alt: 400, + kerning-heading: 0.075em + ); + +// Palette. + $palette: ( + bg: #ffffff, + bg-alt: #f5f6f7, + fg: #7f888f, + fg-bold: #3d4449, + fg-light: #9fa3a6, + border: rgba(210,215,217,0.75), + border-bg: transparentize(#e6ebed, 0.75), + accent: #f56a6a + ); diff --git a/pythoncms/static/themes/front/editorial/assets/sass/libs/_vendor.scss b/pythoncms/static/themes/front/editorial/assets/sass/libs/_vendor.scss new file mode 100644 index 0000000..8f2675c --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/libs/_vendor.scss @@ -0,0 +1,376 @@ +// vendor.scss v1.0 | @ajlkn | MIT licensed */ + +// Vars. + + /// Vendor prefixes. + /// @var {list} + $vendor-prefixes: ( + '-moz-', + '-webkit-', + '-ms-', + '' + ); + + /// Properties that should be vendorized. + /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org + /// @var {list} + $vendor-properties: ( + + // Animation. + 'animation', + 'animation-delay', + 'animation-direction', + 'animation-duration', + 'animation-fill-mode', + 'animation-iteration-count', + 'animation-name', + 'animation-play-state', + 'animation-timing-function', + + // Appearance. + 'appearance', + + // Backdrop filter. + 'backdrop-filter', + + // Background image options. + 'background-clip', + 'background-origin', + 'background-size', + + // Box sizing. + 'box-sizing', + + // Clip path. + 'clip-path', + + // Filter effects. + 'filter', + + // Flexbox. + 'align-content', + 'align-items', + 'align-self', + 'flex', + 'flex-basis', + 'flex-direction', + 'flex-flow', + 'flex-grow', + 'flex-shrink', + 'flex-wrap', + 'justify-content', + 'order', + + // Font feature. + 'font-feature-settings', + 'font-language-override', + 'font-variant-ligatures', + + // Font kerning. + 'font-kerning', + + // Fragmented borders and backgrounds. + 'box-decoration-break', + + // Grid layout. + 'grid-column', + 'grid-column-align', + 'grid-column-end', + 'grid-column-start', + 'grid-row', + 'grid-row-align', + 'grid-row-end', + 'grid-row-start', + 'grid-template-columns', + 'grid-template-rows', + + // Hyphens. + 'hyphens', + 'word-break', + + // Masks. + 'mask', + 'mask-border', + 'mask-border-outset', + 'mask-border-repeat', + 'mask-border-slice', + 'mask-border-source', + 'mask-border-width', + 'mask-clip', + 'mask-composite', + 'mask-image', + 'mask-origin', + 'mask-position', + 'mask-repeat', + 'mask-size', + + // Multicolumn. + 'break-after', + 'break-before', + 'break-inside', + 'column-count', + 'column-fill', + 'column-gap', + 'column-rule', + 'column-rule-color', + 'column-rule-style', + 'column-rule-width', + 'column-span', + 'column-width', + 'columns', + + // Object fit. + 'object-fit', + 'object-position', + + // Regions. + 'flow-from', + 'flow-into', + 'region-fragment', + + // Scroll snap points. + 'scroll-snap-coordinate', + 'scroll-snap-destination', + 'scroll-snap-points-x', + 'scroll-snap-points-y', + 'scroll-snap-type', + + // Shapes. + 'shape-image-threshold', + 'shape-margin', + 'shape-outside', + + // Tab size. + 'tab-size', + + // Text align last. + 'text-align-last', + + // Text decoration. + 'text-decoration-color', + 'text-decoration-line', + 'text-decoration-skip', + 'text-decoration-style', + + // Text emphasis. + 'text-emphasis', + 'text-emphasis-color', + 'text-emphasis-position', + 'text-emphasis-style', + + // Text size adjust. + 'text-size-adjust', + + // Text spacing. + 'text-spacing', + + // Transform. + 'transform', + 'transform-origin', + + // Transform 3D. + 'backface-visibility', + 'perspective', + 'perspective-origin', + 'transform-style', + + // Transition. + 'transition', + 'transition-delay', + 'transition-duration', + 'transition-property', + 'transition-timing-function', + + // Unicode bidi. + 'unicode-bidi', + + // User select. + 'user-select', + + // Writing mode. + 'writing-mode', + + ); + + /// Values that should be vendorized. + /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org + /// @var {list} + $vendor-values: ( + + // Cross fade. + 'cross-fade', + + // Element function. + 'element', + + // Filter function. + 'filter', + + // Flexbox. + 'flex', + 'inline-flex', + + // Grab cursors. + 'grab', + 'grabbing', + + // Gradients. + 'linear-gradient', + 'repeating-linear-gradient', + 'radial-gradient', + 'repeating-radial-gradient', + + // Grid layout. + 'grid', + 'inline-grid', + + // Image set. + 'image-set', + + // Intrinsic width. + 'max-content', + 'min-content', + 'fit-content', + 'fill', + 'fill-available', + 'stretch', + + // Sticky position. + 'sticky', + + // Transform. + 'transform', + + // Zoom cursors. + 'zoom-in', + 'zoom-out', + + ); + +// Functions. + + /// Removes a specific item from a list. + /// @author Hugo Giraudel + /// @param {list} $list List. + /// @param {integer} $index Index. + /// @return {list} Updated list. + @function remove-nth($list, $index) { + + $result: null; + + @if type-of($index) != number { + @warn "$index: #{quote($index)} is not a number for `remove-nth`."; + } + @else if $index == 0 { + @warn "List index 0 must be a non-zero integer for `remove-nth`."; + } + @else if abs($index) > length($list) { + @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`."; + } + @else { + + $result: (); + $index: if($index < 0, length($list) + $index + 1, $index); + + @for $i from 1 through length($list) { + + @if $i != $index { + $result: append($result, nth($list, $i)); + } + + } + + } + + @return $result; + + } + + /// Replaces a substring within another string. + /// @author Hugo Giraudel + /// @param {string} $string String. + /// @param {string} $search Substring. + /// @param {string} $replace Replacement. + /// @return {string} Updated string. + @function str-replace($string, $search, $replace: '') { + + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; + + } + + /// Replaces a substring within each string in a list. + /// @param {list} $strings List of strings. + /// @param {string} $search Substring. + /// @param {string} $replace Replacement. + /// @return {list} Updated list of strings. + @function str-replace-all($strings, $search, $replace: '') { + + @each $string in $strings { + $strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace)); + } + + @return $strings; + + } + +// Mixins. + + /// Wraps @content in vendorized keyframe blocks. + /// @param {string} $name Name. + @mixin keyframes($name) { + + @-moz-keyframes #{$name} { @content; } + @-webkit-keyframes #{$name} { @content; } + @-ms-keyframes #{$name} { @content; } + @keyframes #{$name} { @content; } + + } + + /// Vendorizes a declaration's property and/or value(s). + /// @param {string} $property Property. + /// @param {mixed} $value String/list of value(s). + @mixin vendor($property, $value) { + + // Determine if property should expand. + $expandProperty: index($vendor-properties, $property); + + // Determine if value should expand (and if so, add '-prefix-' placeholder). + $expandValue: false; + + @each $x in $value { + @each $y in $vendor-values { + @if $y == str-slice($x, 1, str-length($y)) { + + $value: set-nth($value, index($value, $x), '-prefix-' + $x); + $expandValue: true; + + } + } + } + + // Expand property? + @if $expandProperty { + @each $vendor in $vendor-prefixes { + #{$vendor}#{$property}: #{str-replace-all($value, '-prefix-', $vendor)}; + } + } + + // Expand just the value? + @elseif $expandValue { + @each $vendor in $vendor-prefixes { + #{$property}: #{str-replace-all($value, '-prefix-', $vendor)}; + } + } + + // Neither? Treat them as a normal declaration. + @else { + #{$property}: #{$value}; + } + + } diff --git a/pythoncms/static/themes/front/editorial/assets/sass/main.scss b/pythoncms/static/themes/front/editorial/assets/sass/main.scss new file mode 100644 index 0000000..6001ca2 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/assets/sass/main.scss @@ -0,0 +1,62 @@ +@import 'libs/vars'; +@import 'libs/functions'; +@import 'libs/mixins'; +@import 'libs/vendor'; +@import 'libs/breakpoints'; +@import 'libs/html-grid'; +@import 'fontawesome-all.min.css'; +@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600,400italic,600italic|Roboto+Slab:400,700'); + +/* + Editorial by HTML5 UP + html5up.net | @ajlkn + Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +*/ + +// Breakpoints. + + @include breakpoints(( + xlarge: ( 1281px, 1680px ), + large: ( 981px, 1280px ), + medium: ( 737px, 980px ), + small: ( 481px, 736px ), + xsmall: ( 361px, 480px ), + xxsmall: ( null, 360px ), + xlarge-to-max: '(min-width: 1681px)', + small-to-xlarge: '(min-width: 481px) and (max-width: 1680px)' + )); + +// Base. + + @import 'base/reset'; + @import 'base/page'; + @import 'base/typography'; + +// Component. + + @import 'components/row'; + @import 'components/section'; + @import 'components/form'; + @import 'components/box'; + @import 'components/icon'; + @import 'components/image'; + @import 'components/list'; + @import 'components/actions'; + @import 'components/icons'; + @import 'components/contact'; + @import 'components/pagination'; + @import 'components/table'; + @import 'components/button'; + @import 'components/mini-posts'; + @import 'components/features'; + @import 'components/posts'; + +// Layout. + + @import 'layout/wrapper'; + @import 'layout/main'; + @import 'layout/sidebar'; + @import 'layout/header'; + @import 'layout/banner'; + @import 'layout/footer'; + @import 'layout/menu'; diff --git a/pythoncms/static/themes/front/editorial/base.html b/pythoncms/static/themes/front/editorial/base.html new file mode 100644 index 0000000..32510e1 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/base.html @@ -0,0 +1,27 @@ + + + + + Editorial by HTML5 UP + + + + + + {%block body%} + + + {%endblock%} + + + + + + + + + diff --git a/pythoncms/static/themes/front/editorial/elements.html b/pythoncms/static/themes/front/editorial/elements.html new file mode 100644 index 0000000..4aecc06 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/elements.html @@ -0,0 +1,543 @@ + + + + + Elements - Editorial by HTML5 UP + + + + + + + +
+ + +
+
+ + + + + +
+
+

Elements

+
+ + +

Sample Content

+

Praesent ac adipiscing ullamcorper semper ut amet ac risus. Lorem sapien ut odio odio nunc. Ac adipiscing nibh porttitor erat risus justo adipiscing adipiscing amet placerat accumsan. Vis. Faucibus odio magna tempus adipiscing a non. In mi primis arcu ut non accumsan vivamus ac blandit adipiscing adipiscing arcu metus praesent turpis eu ac lacinia nunc ac commodo gravida adipiscing eget accumsan ac nunc adipiscing adipiscing lorem ipsum dolor sit amet nullam veroeros adipiscing.

+
+
+

Sem turpis amet semper

+

Nunc lacinia ante nunc ac lobortis. Interdum adipiscing gravida odio porttitor sem non mi integer non faucibus ornare mi ut ante amet placerat aliquet. Volutpat commodo eu sed ante lacinia. Sapien a lorem in integer ornare praesent commodo adipiscing arcu in massa commodo lorem accumsan at odio massa ac ac. Semper adipiscing varius montes viverra nibh in adipiscing blandit tempus accumsan.

+
+
+

Magna odio tempus commodo

+

In arcu accumsan arcu adipiscing accumsan orci ac. Felis id enim aliquet. Accumsan ac integer lobortis commodo ornare aliquet accumsan erat tempus amet porttitor. Ante commodo blandit adipiscing integer semper orci eget. Faucibus commodo adipiscing mi eu nullam accumsan morbi arcu ornare odio mi adipiscing nascetur lacus ac interdum morbi accumsan vis mi accumsan.

+
+ +
+

Interdum sapien gravida

+

Nunc lacinia ante nunc ac lobortis. Interdum adipiscing gravida odio porttitor sem non mi integer non faucibus ornare mi ut ante amet placerat aliquet. Volutpat eu sed ante lacinia sapien lorem accumsan varius montes viverra nibh in adipiscing blandit.

+
+
+

Faucibus consequat lorem

+

Nunc lacinia ante nunc ac lobortis. Interdum adipiscing gravida odio porttitor sem non mi integer non faucibus ornare mi ut ante amet placerat aliquet. Volutpat eu sed ante lacinia sapien lorem accumsan varius montes viverra nibh in adipiscing blandit.

+
+
+

Accumsan montes viverra

+

Nunc lacinia ante nunc ac lobortis. Interdum adipiscing gravida odio porttitor sem non mi integer non faucibus ornare mi ut ante amet placerat aliquet. Volutpat eu sed ante lacinia sapien lorem accumsan varius montes viverra nibh in adipiscing blandit.

+
+
+ +
+ + +

Elements

+
+
+ + +

Text

+

This is bold and this is strong. This is italic and this is emphasized. + This is superscript text and this is subscript text. + This is underlined and this is code: for (;;) { ... }. + Finally, this is a link.

+
+

Heading Level 2

+

Heading Level 3

+

Heading Level 4

+
+

Nunc lacinia ante nunc ac lobortis. Interdum adipiscing gravida odio porttitor sem non mi integer non faucibus ornare mi ut ante amet placerat aliquet. Volutpat eu sed ante lacinia sapien lorem accumsan varius montes viverra nibh in adipiscing blandit tempus accumsan.

+ + +

Lists

+
+
+ +

Unordered

+
    +
  • Dolor etiam magna etiam.
  • +
  • Sagittis lorem eleifend.
  • +
  • Felis dolore viverra.
  • +
+ +

Alternate

+
    +
  • Dolor etiam magna etiam.
  • +
  • Sagittis lorem eleifend.
  • +
  • Felis feugiat viverra.
  • +
+ +
+
+ +

Ordered

+
    +
  1. Dolor etiam magna etiam.
  2. +
  3. Etiam vel lorem sed viverra.
  4. +
  5. Felis dolore viverra.
  6. +
  7. Dolor etiam magna etiam.
  8. +
  9. Etiam vel lorem sed viverra.
  10. +
  11. Felis dolore viverra.
  12. +
+ +

Icons

+ + +
+
+

Definition

+
+
Item1
+
+

Lorem ipsum dolor vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Lorem ipsum dolor.

+
+
Item2
+
+

Lorem ipsum dolor vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Lorem ipsum dolor.

+
+
Item3
+
+

Lorem ipsum dolor vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Lorem ipsum dolor.

+
+
+ +

Actions

+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +

Pagination

+ + + +

Blockquote

+
Lorem ipsum dolor vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Lorem ipsum dolor. Lorem ipsum dolor vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus.
+ + +

Table

+ +

Default

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionPrice
Item1Ante turpis integer aliquet porttitor.29.99
Item2Vis ac commodo adipiscing arcu aliquet.19.99
Item3 Morbi faucibus arcu accumsan lorem.29.99
Item4Vitae integer tempus condimentum.19.99
Item5Ante turpis integer aliquet porttitor.29.99
100.00
+
+ +

Alternate

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionPrice
Item1Ante turpis integer aliquet porttitor.29.99
Item2Vis ac commodo adipiscing arcu aliquet.19.99
Item3 Morbi faucibus arcu accumsan lorem.29.99
Item4Vitae integer tempus condimentum.19.99
Item5Ante turpis integer aliquet porttitor.29.99
100.00
+
+ +
+
+ + +

Buttons

+ + + + + + +
    +
  • Primary
  • +
  • Default
  • +
+ + +

Form

+ +
+
+
+ +
+
+ +
+ +
+ +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+ +
+
    +
  • +
  • +
+
+
+
+ + +

Image

+ +

Fit

+ +
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+ +

Left & Right

+

Lorem ipsum dolor sit accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.

+

Lorem ipsum dolor sit accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.

+ + +

Box

+
+

Felis sagittis eget tempus primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Magna sed etiam ante ipsum primis in faucibus vestibulum.

+
+ + +

Preformatted

+
i = 0;
+
+while (!deck.isInOrder()) {
+    print 'Iteration ' + i;
+    deck.shuffle();
+    i++;
+}
+
+print 'It took ' + i + ' iterations to sort the deck.';
+
+ +
+
+ +
+ +
+
+ + + + +
+ + + + + + + + + + diff --git a/pythoncms/static/themes/front/editorial/generic.html b/pythoncms/static/themes/front/editorial/generic.html new file mode 100644 index 0000000..e5515d8 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/generic.html @@ -0,0 +1,172 @@ + + + + + Generic - Editorial by HTML5 UP + + + + + + + +
+ + +
+
+ + + + + +
+
+

Generic

+
+ + + +

Donec eget ex magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fergiat. Pellentesque in mi eu massa lacinia malesuada et a elit. Donec urna ex, lacinia in purus ac, pretium pulvinar mauris. Curabitur sapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dapibus rutrum facilisis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam tristique libero eu nibh porttitor fermentum. Nullam venenatis erat id vehicula viverra. Nunc ultrices eros ut ultricies condimentum. Mauris risus lacus, blandit sit amet venenatis non, bibendum vitae dolor. Nunc lorem mauris, fringilla in aliquam at, euismod in lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non lorem sit amet elit placerat maximus. Pellentesque aliquam maximus risus, vel sed vehicula.

+

Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fersapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique lorem ipsum dolor.

+ +
+ +

Interdum sed dapibus

+

Donec eget ex magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fergiat. Pellentesque in mi eu massa lacinia malesuada et a elit. Donec urna ex, lacinia in purus ac, pretium pulvinar mauris. Curabitur sapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dapibus rutrum facilisis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam tristique libero eu nibh porttitor fermentum. Nullam venenatis erat id vehicula viverra. Nunc ultrices eros ut ultricies condimentum. Mauris risus lacus, blandit sit amet venenatis non, bibendum vitae dolor. Nunc lorem mauris, fringilla in aliquam at, euismod in lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non lorem sit amet elit placerat maximus. Pellentesque aliquam maximus risus, vel sed vehicula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fersapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique lorem ipsum dolor.

+ +
+ +

Magna etiam veroeros

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dapibus rutrum facilisis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam tristique libero eu nibh porttitor fermentum. Nullam venenatis erat id vehicula viverra. Nunc ultrices eros ut ultricies condimentum. Mauris risus lacus, blandit sit amet venenatis non, bibendum vitae dolor. Nunc lorem mauris, fringilla in aliquam at, euismod in lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non lorem sit amet elit placerat maximus. Pellentesque aliquam maximus risus, vel sed vehicula.

+

Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fersapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique lorem ipsum dolor.

+ +
+ +

Lorem aliquam bibendum

+

Donec eget ex magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fergiat. Pellentesque in mi eu massa lacinia malesuada et a elit. Donec urna ex, lacinia in purus ac, pretium pulvinar mauris. Curabitur sapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dapibus rutrum facilisis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam tristique libero eu nibh porttitor fermentum. Nullam venenatis erat id vehicula viverra. Nunc ultrices eros ut ultricies condimentum. Mauris risus lacus, blandit sit amet venenatis non, bibendum vitae dolor. Nunc lorem mauris, fringilla in aliquam at, euismod in lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non lorem sit amet elit placerat maximus. Pellentesque aliquam maximus risus, vel sed vehicula.

+ +
+ +
+
+ + + + +
+ + + + + + + + + + diff --git a/pythoncms/static/themes/front/editorial/images/pic01.jpg b/pythoncms/static/themes/front/editorial/images/pic01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7add3889394f8764bcb373e8e123fe9269c5e2a3 GIT binary patch literal 20660 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 literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic05.jpg b/pythoncms/static/themes/front/editorial/images/pic05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cda4792bcba173eaeeaeae7ae3dd05107ab08b67 GIT binary patch literal 21497 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 literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic06.jpg b/pythoncms/static/themes/front/editorial/images/pic06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..891b92f48a986140b889b5cd2426f801f188d815 GIT binary patch literal 21564 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 literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic07.jpg b/pythoncms/static/themes/front/editorial/images/pic07.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18f7248dfff77d5e6e86580718fd3f4a2e6ad373 GIT binary patch literal 10854 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 literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic08.jpg b/pythoncms/static/themes/front/editorial/images/pic08.jpg new file mode 100644 index 0000000000000000000000000000000000000000..844923fc8685f5f84328078d2de4e3505b24b21f GIT binary patch literal 10934 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 Ufv11WMST2}RS5=Cx0A{L0}{aPegFUf literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic09.jpg b/pythoncms/static/themes/front/editorial/images/pic09.jpg new file mode 100644 index 0000000000000000000000000000000000000000..742eece0a9b201b8ad2c82dc790ad00525b2e27a GIT binary patch literal 10350 zcmbVwcRbtQ_i$pwC~7onQ?oTngjlsjX>Dp2B{mTvHdVBg8b$4usg-`DfUb6&~&ec$(cTdP#&X61y6#@y1`%j?%Lo%IM1(Iw#Z6dK zL+D1BY8WyA>5g#`3Pbw&2dRds3;)ermD2vxEh{YaHwwmAU0C~%R3TeqGa+3R+FeNT zI#dQB2Z0E|VAmlEiZB>NT1Z|FA}=dP`N3o$3aW}QRe2?$e}OPX8rsc6)k07IU$Q7) z>can8RA^}E^-$<_6xvf3qN1Ymhljkp3sxB=T<#dhS68w08i;8|5$b zhog%tDj1_KOquCFmw*f~HvSLe|Eet{^3S^d#ty<*xc|>I{wsEnRd|5Atc80JDj1D$ zr=W}co0y`z|F@t&h?Lo=nxefao8sc9he8A+-Tg6!dg{WIk?U^WZmJL%TuuQZ4~4^2 zD1Qh<2P!8A*MUQnbhYK>;Sl+M^Z2i{3NU4;o{oYFOj!p4fy1<+6fzwJm=aV$MOhi5 z{BK%A{~(NuKf?Xra=rh^RiGeK#QZ;LRdvzsE*KQr3Wf6fw*{Dap)jZ*FI0e#t|d(9 zs*Sh58!9yD+Mn(D=W6xb(cU5MZu)2xQs{5}s(Swy`6^0sa&pRWePwMG*q?Q)D8m($ z<>lZIIhcYDOi51oU$k!jKRT18Oh)#Par|$_^6xH+1^#LN$Mh*5|8X97e~QPTDXww; z6TtGf!2{ghQCtvsz5sX#pr-l*lqWSUH8nLYEe$m_4K0ZF4}j=FbQA#5(=#wKGBVIJ z{S7RCfb~BBq^6+(fj~_3^i1q5Of2k|{)}8=`+J=2pD)&bz5YYBeD0odpPwLl?i zARB;+4M@!fJnsbr0f7I6|AY`KAb^^dhW`KR{j&}lYARMBfC@;NKQ$GInt}%e0NJRn z03htz=F~2M!m%0h&pG~4|9)J@V#QU2h>p{3U<3Y#@xL19^8h9aAr%`n8$c6qdO)o7 z`^grz3YxoU7@1n zRk5u+ynsx>bmijiP6b1xV;$sBQ{NrWEA#xW3BF4_aH}j`u3~sHAbmxI3N7Ruu@9(|(tG=|=2N-F!J;dw3e`QI5$C*C2JeGQytia`9 zDJ$~E?QtmqGj2cqMyHqW?fzC8aak)WH7cEZP&xOtX_S{t)B_Tcm5Xa}@8-R6Yu7Y` zCcE98j#TYyK2FMOf}(L(KJqXhm-4LovD%Bnc8|Qo%Brl#y=`-G3*GIK5ARU>#ea(5 z!wau}dJ3rbF1mQrOmfLquG2DQbm=KUo;1|Zx*Qc_46bl$7U)`)yReOI0Lx^4?GujZ z_alIj=ttX~JM^}rs$Q4V2%VXR_8*KQOQXR#Qx)buDP_tdU#Ktx%kL|S zi7E|bsM6h$8vG2<|8itFqut|QJIs;i`O2v;7H8nIcaYLQSkghLo$eWs0Hzs8bne!s zQB8{>2N-5^zmG-Jyit^%auTKU4k>A82_iK%=6db2HA1n|%^G(N!#@99d%XY;>Vi^@ zO7G?4^*@A)-}B6EA^;YO%s~sD&*x2!s9xfkY(IACI~96~l|Be`b+RLb#+z}I=!AW= zZX~|8qk~hAV460)8}uV1DVlorbTNA=Y_pDxcW`P>z!KAl^MMk^K(nVkU^@xr1!)w| zg|9d&VV1nXZuRC%4yGDU#q#@5zucd zad^{_PBWLY5t#TKqB&s(O(BIxzb5t)qcZPZU;sOgT zCQD=wJAcBusP?#H^iw$)nL!B2^WaNZm4z-g6bH()F*}hQ7h% z9eLHDL~Wi1#D*hO2Dh=Pt+Ur=D)YG)O^vB*26A+hgmkZciEd)S(HG5RrIw+Mb~vz8 zw`rB!Lst`i9*$dPYjq@O2uInOoTbHYp=6%O>5FFSmajS5_3iU~T7Gu>5$)~_oJ|J2 z#@zChysWJPz4g&z9QO0|-fo2o?lN(i#FAbw9`8iW%Cs{bV7jcOA++ozfBV|BXQ!9M zPwPd;AKFa8N!z#wbM_~ZQ4c|a(Np7hcYU~4()SuxC2*q;tWS`>Rsw3RgYD!jGk+9& zbI+wit>E8B1POYXq}41VsUxoncvMtMvwQR1F=J5YJWkd{$6ZwIG!X5`9=CsCjhk(7 znP&=F)~fovSAE0qr0NTzGx#imd7yE$8JwRf*RiJv4kvmXFYvjB^saiUJ~ukCrxw!x zA%{8*rU}n(i1K{4ZWk)hel2y~-EMy#cIM!v7&YA@?go=%+bycc-bp~YK;){`n=I<& z=UfJW1;=#8+Bd98VN-3_g_JIu9MO${MuM!&9YGGx{FgU6KVew>a;mdjO4QWP`jQ{A z!d&IJk5-NeV4k|2A-{F9K>J1PiNSm$-tqZvZS|IKLkoStZ>Li`{B7I`l4UWH3ZZo) z8yWYSR~)Uj$GwZ)j94bVNI?5-?kSk@{$m5`|3t9g0Ds2^MzR+cZcIw;UTUXucShd)88GeVh`W-_b4b|Q6 z%;H{AVWbTU9gSirR;9UGPfe((%u~=2tQqLCKwA!tul`*OLawp*`8rqY$o|6HkI9~b zK3)%ZC-_{uDWDkJG~$dhripr_7v!Eu7kxI*wD6LPFQcc231CuLLs$Yeksd>rN^ln@m`oflO z(#{C|+-(5Ky}-Sd)*d_VmoiOtXD^T89;a~2i3>JFAti?t%%`n$~uv}M6*YJ`QG;EC`=*m zV85Bjrx@|}t>0YMLi%4bvpx8jAlUK>izD$)iK!Kmh1J?6?J6C_0=@etxUwcxsTph% zhpuoB(-d4?7G<+=&o3ft6vW+vTsRczXEY7p!KOZySsO8mZ4xK|ejZDk>Z(74xw)Mx zaMP?DlH?w!kRu6I4&@frZ%+_kf&^wKSvv>Sc#V411J%50(3f*L(NHea8LjdL+abT7 z2z6?0pYi6KzM5&Ok)e}T>i~=;uR$Z-@`TpH^0Rrgn%a^6&1ewPqn1To=zY@O$BG(< z%TIJdN?I50&oi&8aC&-CfLOt{UhlY$?5c(K9rCz-PJ5?t=b4Eo z&2D#`{Xd9ke%rJ`wj(dbc}cSk!DP?qx%a7bQo0VZ8xo(dxS;n(%gVYXi2(x@eW!Af z1jQxA@U_$Z-mY|GVDqzrrzoGfc&5`P8x5->Mgyi5L#A>snL|>6varcXSxgRgEz;xV znLfDp0cLF%d;hjg;$YgZUBX9PGVRW=Pd#SLu?L5}!x+^gFq^vht)&4390( zittop%l2+raUCi*iv)Q;W|;aLe>vsl^ZX`_k_L?|kl<7gA-49}Ok0fO`={nbCY=(&WkdhhuxVS8r$$V*&i29hsqoU$L` zBWZKu_pS><^@E`3x7#m&FP9iW@fhcnrH43G78pbYe`~I$=U2T|PK327vc96+Ky%y9 z338_V-Ahq+!1}Fn($|u&rx^2%OOMk!_#;9WCpoE<7oKHVQ!?P!-N_RUwkn+RH0OYn z>j)kuSj`J=iEx+Ce~reGnxDm8GFN9f6EU~8{@k#h7uLFswQjr7I+96^Rv!V^gjM-8 za4`PpYPy&!9wHi#Tx#3KVXt5$ou8cpvYd$+<~3ijJX*1B<)m@znFb=n7HktriDL8> zZyxLYj#mX8-jtluGkz7Vz}r7sr;V2=&3JHhSH~LYZrRDSMQw<4vp?GqT ze~(65;AX!Xhl3RVsUx`jf>SmBJ%dLPUQ!N<4}v(%R`)_Kb5EN4zqj8=u~qHyd=(#) z`h+{1lT~A>UCQjQS-Zy)p4=?QUP@Q1qVha*j&JFIRRnI_7rxf@6n!g(d)%s^>L7{v z^4=*FI{|cv`Vo^!UJ9k;azj%zHnjH^7Q!caa}O%HbAqm`ql3q-*6FUUSu?q0O{o&V zC=@>p>eekGe#8TEfwdN&->r*PpM;B;$_e>=sHA%!5AnYtv^vMTu5 zFqP)zgC~9)5$+Jxi#>zETmif8ae7C4Ga+WOZbEdY$TZ9REiC=lr1j0@Q#E8aHiu_% zt7)=tv&EQ(bjS-&aDuxn)4ftKU$@w=_||2-T)vB4UuuT%xAvn|3*w=7jFZ;0KoO`T z0yb(acOdUnI0$>qej(KcNVD7G2i?LJyJsnOf zLi0m8HGed@#s}S1ZaQGW+KVs)%iO;P;i}dq2jY^YY->=A#b{&`52JJ6Ly1w4(f~qp z*^Il@I=vV2iBl=JB^u28mDeTU2D*DtmCo)>;KzEk{@SwFX}_tYAKsKL-@mwtZK$!I zyrW~ed#V6Hc@-MH49&dU9qCm*r&m*68~J)Z((&tL6{i^Ql z2-+0+Ec%fqU3(iF{0nh)x^bIrZaWojeb>JHbtmPrq8$~b<1EN7+_q>V*oU#sUT2?D zmk#Y)nrDs-7hW`e>mt;LVMcoU4YHz=wvPy6ym=+C1PkW)3GFYqK=!T=o{OXL=AasG z9Xq)Uapnnl^e>KkL+z_d>ad;KAFgxm&Ur?KyF6FJFK~uMt?GtI>QhcR8b6PZ>c2Xc zRkkW<)11>J6q{P_XO$&pWuoP5PKwL>{oCnZcsC3aL7x%Rf-~9!E&YmYIhUbrMXJd; z>F0n#68PgJB;65os5?yaY~UkV0(nWLGff&@@a-}=7--u#BrWAXq6@z@N7b}bqJ|*j zS?+X6o&zdzcFwss4+&y5fHTRRyBQUg{x{c8O3T*p`FQXZoP9^|<6YU>vX{5IwfuAB zu4ZB3<+{wckNJDiq2ty$q??klimuqindt~G2Cqury|^xyVU%ioP+ed4T+urt@&eqh zllbv7xL1E6nsQinK5;B_zvp_tm=gQGOAgWBTBT#--d87E_&)bfQTI{YuN?M!)KR09J6B!at6T4k_435{2Ft3=7{dmTcAUa$ z)hzQ&q=c!UyVjv=IFV)ZTRAy#xT!SYKY-{ z&eo@|oLo%$y#TkLJ2Z+)E-cqv!mzZc1XdNrN*K3;FuY|tq?_k}1ZXi8NwMkVxq5t zRBlvKep7QVvZM}Wd`U2YPaDSn#kr*$`;92&li}JH)UB>gwo!Wg<2HXsjHQEd%?7mss;9PI)!fUr2<A6*NeI=is}5@osFK!BnCVYt?ocHG6^ ze97rfPyhAlU7FT~ZUvs^YnRte;E5sB$D!k9`i+hguy_%T-R`pHSWrhi`(ql8lSnW2 zgD>7hgV{k<>Y?H@8e;xx9zj2O+T;D?IY6NPE`s+v?eUU^xhFrg#ag4CaTa$WuxyoH zIAqwX+J4Z%w1SnDx@0tNI-DkO(=M#?i>gW46Ibbk*+eunl}=lBknTyL@~F+LxZ$W3 z>S{r)V}ewq?V(2iUMHf^BzAhm;i^2VgL~%v30%AqPtX=yku=%Hk4LiefK>hQ;Z{-b z?{R^bam$BaJ)_9v<&fa#DN!X(7Bg!t-3Ni{?OxBN=(H^ zeP_8fb=v3PXL4Ed1Y_ka&U+i0Zb>tU{Z^B{NX)M0brn(HpEM_3^N-F!UU|AW77Z%M ze>0Nw^CxDn7(A3a>Q&Xk_l^2st3o8E@V(HX;$X`Hob$bPYLD!GQ~qA67O%zh0h|03 z%PX#hSMyhEQZowg%ee=p8`B~!tXK?%Kfl;s3I@ygGJ*3?5XiNO1vvY6&T{}YgbUIc zJW12uthwOMDFG=p20K4}c7a|g{Q$2`9H+yibRDHF_%I#neRzLJzp9QKw+*xNFzB1$ z7lz^i&>h4%rgh8)H96T8?l)`L0zT|o%(J05kA%Ubin11@M5Rwmps?sshLQ2m8HtGy`t4ex|$7$<1z*a$^ zE_0^RCmzSmjO(AU=PLSnr(SWCx;lREh)_1`yrA!vq^g$p8-KCHwGp{7xFkd#*E#X_ zwR5=H8y-#Z;03b_FFw_Ui9C-#^kP^~sJLzWDSGpHMcFKuubI_K$4?46$G{_3SFvK; z@+3aU*HuQdw71$wpl!FJQm1;_Zup&OBvKjgYs>J07;{y`D=B}cqSiaO#?%jz^dsF7 z*c4bNZS`Jdv7a<LK3-AW$2w<_N7EK3jRGHPeP^4-FgJbTW7-o#M`*r^r2;4S{t%guP$#pGxP^Ul8?%$p z-sauW&;Q< zZgJQXSN77rDMeiLcWk0|_Qq%caykODiw!lAxcp>X_Z;xq6M5)qm(G!@P4IDQncX9k<=R+A*`0a^UXS`B z0{v`-2rIGn3s)}uy0-JF)Q8bIPwwL4CLMUkfPLm02z2Xua?RU77noR4UyLK`6IkWl zA{SqdPWkQvsTq=el`lzJ58ZFoXE2>}DQrDp&PmM;nhR%0=+=N(EAx-}*9Oz6>E_U6 z_gz7#GLQ_+eS5mcuP1LtN@y-5Ln&)v)Jp1?RjF`wAM&C1npj_rehmgo z`Hr#X;G4+{Jd#oz9nb}q`S?e>qUAAfO>8c{b_Ca~H#+UQgRc~MC<2>nF3JqZ1i(s- zFWE20f0o~fHYkR347%L=t5wCl53Nx^1(UWZaZ9V`9m6HRoU6AMeD;@Wq{&e{vnk)Q z-w+4x=aHlyQ2th+?dbTUNgKsNTc*O#U8Xm+a(t}0bb!ysP6*e$(*leG&&-qZcFNwc zd{SHC`8WmNiNGA|L{lbR0}uw9AHUf^0Tb^3z}(om9g%{ zn``SWte}r6T7Evvr76l)7iC(0CK}Uzq|=btC{FYWS1$8o6wpHd%@L4u&iT z$?Yv@J4|;bSh?6NS*nvSMp|u9eQNx)^#xHIZ%XBp!z8V|myYO;MQ6_VwAx5qTA0xO z@nz=98dx}J0+}}d<-@o7OSW(KY$o5Ulg*n({1&z;sb1kXbd6MtPv^8Nbj?45lITc*) zXP=4sBt24EN1Eh53Hy=x;nl!cIiW23!yAX_#-dHL3yw|M)_E6{qYd{l5f`B$sm}r0 zd0)qj_dpwwOH=ZGGlHn@I8OGv_Bg+r&Jz>nI=B{4&d30QO^Q;bxL`dT7&vJLa$Xs? zd1%{|)50A%^V5f^KLf$sz@WTSR%6|GcP%_4;>XQsKvZ^3*o@j0C{G-&DHZ)w91(tI zFZuQM-6}qux}%-yQgrGgVz%6iBr37LPX4hob!E^ zjXt5*7QPr$-AH}YTtqZERv$gOW_=C-dyJT7DEFIo#~$8z%yVCH*3+uH9Pkc7DwV_Vr!f68!hZ#m(`r}p{RU`iF;2!m%mdE;N*w;J78QG0jS z8a<yFMc|eh zo;jNAgRHG&JdaFN4kGc|#V2j#ZR{56itidxRj+J+TU9c(T502u&L%v)_VLTQUXmiY zJ_R|uygIVK)-f zvt71rq95y}&uDqzq<3kw*5DV2HTI|Y*^oIJM!ZGV6ZE;vzW(?NAW4NaRs(k2V*X*zr16T7Rc~6lBeSLMd>$r zy5!?cds}@oUfU-9(76;>jE$y9Uw&oNXEGnJ3HFIe^T>TOOj_}4RjK0rnpeOLpRR$^ z;7fwXh$jcNAFrPsvE0{x|7li5>znKS_T(AX6*F=D$i1}MWU!0S?L=+*Ui~aqRD2>eJ9V>>hrRqxOOX^51a$Me6Q}}?&bX)Evu=vqy7sb_=T>V zP#fBwo?D%$cWmm&T3b`}mssEEM_kA>K)sx+(-AY%ZGU;# zN7-_6DH1674^lNydenwejgHFl7c$Vn^m*=$+mGmUi@x*I|3xl_i^$*Pz{boa?v1k^ zJ~ibY{Si^>RB%niVY;Pm!>^KSSkEL5R{f^PIU9E=Fs+>qCDt0V5x2Q2!rx;IDkHg! zx^pkEugz#1HfMh5Wi~Yp-of5|Rx2v*4pG0XJjIxk<6DqqRj9rhO}&=T>@Id_Vn+#c zF2PUgZAd=+zqa`IDj&eVA*4fext5@+aZ!5fBQG|@HF3Yn+9t9LiSM&hOb#y^PTDXK zo0M4_Tms{j$>WyadPJUFqz~$Yvibne0p%m1-_?vLnfF%33+uKkA3p4z6p zLB*_0nza$lg;GLY$jb-I+U!zpR&mBPN8cs+T3?2wh=&}`H6s;N`oBf_hkl!OlE zv!|qzYg&?W&+G_|LweZlvnG!L&k4a3R!K_f4g5CtkXpAptNYn+y%j5Q=Vp_`gx;V zQcoqU%tu-UIignjZTn*NAo4%dtRuT%cs0&@Rh%iUf!kc;Y`$@Q5wPzuGT`&M{{;z% B6@CB! literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic10.jpg b/pythoncms/static/themes/front/editorial/images/pic10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2e9ba306ef0e31f2929e6d09a9fa43f91d0df7f7 GIT binary patch literal 70746 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 literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/images/pic11.jpg b/pythoncms/static/themes/front/editorial/images/pic11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..56cae8c7b1d351fc8d29e12ec128c82f7f0a4479 GIT binary patch literal 99292 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
#)R41$wF*{@G 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 E2fQ|ydH?_b literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/editorial/index.html b/pythoncms/static/themes/front/editorial/index.html new file mode 100644 index 0000000..bd9aa22 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/index.html @@ -0,0 +1,144 @@ +{%extends 'editorial/base.html'%} + + +{%block body%} + + +

+ + +
+
+ + + + + + + + +
+
+

Erat lacinia

+
+
+
+ +
+

Portitor ullamcorper

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+
+
+
+ +
+

Sapien veroeros

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+
+
+
+ +
+

Quam lorem ipsum

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+
+
+
+ +
+

Sed magna finibus

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+
+
+
+
+ + +
+
+

Ipsum sed dolor

+
+
+
+ +

Interdum aenean

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+ +
+
+ +

Nulla amet dolore

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+ +
+
+ +

Tempus ullamcorper

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+ +
+
+ +

Sed etiam facilis

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+ +
+
+ +

Feugiat lorem aenean

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+ +
+
+ +

Amet varius aliquam

+

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

+ +
+
+
+ +
+
+ + {%include 'editorial/sections/sidebar.html'%} + +
+ +{%endblock%} diff --git a/pythoncms/static/themes/front/editorial/info.json b/pythoncms/static/themes/front/editorial/info.json new file mode 100644 index 0000000..e00ba90 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/info.json @@ -0,0 +1,4 @@ +{ + "author": "ARJ", + "version": "1.0.20000000000003" +} diff --git a/pythoncms/static/themes/front/editorial/page.html b/pythoncms/static/themes/front/editorial/page.html new file mode 100644 index 0000000..3d357ff --- /dev/null +++ b/pythoncms/static/themes/front/editorial/page.html @@ -0,0 +1,43 @@ +{%extends 'editorial/base.html'%} + + +{%block body%} + + +
+ + +
+
+ + + + + +
+
+

{{page.title}}

+
+ +

{{page.get_content()}}

+ +
+ +
+
+ + {%include 'editorial/sections/sidebar.html'%} + +
+ + +{%endblock%} diff --git a/pythoncms/static/themes/front/editorial/render_demo.html b/pythoncms/static/themes/front/editorial/render_demo.html new file mode 100644 index 0000000..b42ae9b --- /dev/null +++ b/pythoncms/static/themes/front/editorial/render_demo.html @@ -0,0 +1,3 @@ + +

WWW Index

+

Fruit {{ fruit }}

diff --git a/pythoncms/static/themes/front/editorial/sections/footer.html b/pythoncms/static/themes/front/editorial/sections/footer.html new file mode 100644 index 0000000..e69de29 diff --git a/pythoncms/static/themes/front/editorial/sections/nav.html b/pythoncms/static/themes/front/editorial/sections/nav.html new file mode 100644 index 0000000..e69de29 diff --git a/pythoncms/static/themes/front/editorial/sections/resources.html b/pythoncms/static/themes/front/editorial/sections/resources.html new file mode 100644 index 0000000..e69de29 diff --git a/pythoncms/static/themes/front/editorial/sections/sidebar.html b/pythoncms/static/themes/front/editorial/sections/sidebar.html new file mode 100644 index 0000000..aa66b58 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/sections/sidebar.html @@ -0,0 +1,91 @@ + + diff --git a/pythoncms/static/themes/front/editorial/styles.css b/pythoncms/static/themes/front/editorial/styles.css new file mode 100644 index 0000000..3f9cc33 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/styles.css @@ -0,0 +1,41 @@ + + html { + scroll-behavior: smooth; + } + .suggest { + + } + + .suggest span { + padding-left: 5px; + padding-right: 5px; + margin: 5px; + min-width: 50px; + } + + a{ + text-decoration: inherit; + color: inherit; + } + a:hover{ + text-decoration: inherit; + color: inherit; + } + + #flashed-messages{ + padding: 5px; + position: fixed; + right: 5px; + top: 5px; + z-index: 10; + height: 300px; + overflow-y: scroll; + + } + #flashed-messages::-webkit-scrollbar { + display: none; + } + /* Hide scrollbar for IE and Edge */ + #flashed-messages{ + -ms-overflow-style: none; + } diff --git a/pythoncms/static/themes/front/hyperspace/LICENSE.txt b/pythoncms/static/themes/front/hyperspace/LICENSE.txt new file mode 100644 index 0000000..d447b56 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/LICENSE.txt @@ -0,0 +1,63 @@ +Creative Commons Attribution 3.0 Unported +http://creativecommons.org/licenses/by/3.0/ + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +1. Definitions + + 1. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + 2. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. + 3. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. + 4. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + 5. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + 6. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + 7. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + 8. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + 9. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + + 1. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; + 2. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; + 3. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, + 4. to Distribute and Publicly Perform Adaptations. + 5. + + For the avoidance of doubt: + 1. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + 2. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, + 3. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + + 1. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested. + 2. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. + 3. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + 1. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. + 2. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + +8. Miscellaneous + + 1. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + 2. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + 3. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + 4. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + 5. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + 6. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. diff --git a/pythoncms/static/themes/front/hyperspace/README.txt b/pythoncms/static/themes/front/hyperspace/README.txt new file mode 100644 index 0000000..7fbf4ee --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/README.txt @@ -0,0 +1,33 @@ +Hyperspace by HTML5 UP +html5up.net | @ajlkn +Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) + + +So I've had the wireframe for this particular design kicking around for some time, but with all +the other interesting (and in some cases, semi-secret) projects I've been working on it took me +a little while to get to actually designing and coding it. Fortunately, things have eased up +enough for me to finaly get around to it, so I'm happy to introduce Hyperspace: a fun, blocky, +one-page design with a lot of color, a bit of animation, and an additional "generic" page template +(because hey, even one-page sites usually need an interior page or two). Hope you dig it :) + +Demo images* courtesy of Unsplash, a radtastic collection of CC0 (public domain) images +you can use for pretty much whatever. + +(* = not included) + +AJ +aj@lkn.io | @ajlkn + + +Credits: + + Demo Images: + Unsplash (unsplash.com) + + Icons: + Font Awesome (fontawesome.io) + + Other: + jQuery (jquery.com) + Scrollex (github.com/ajlkn/jquery.scrollex) + Responsive Tools (github.com/ajlkn/responsive-tools) diff --git a/pythoncms/static/themes/front/hyperspace/assets/css/fontawesome-all.min.css b/pythoncms/static/themes/front/hyperspace/assets/css/fontawesome-all.min.css new file mode 100644 index 0000000..96766f3 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/css/fontawesome-all.min.css @@ -0,0 +1,101 @@ +/*! + * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} diff --git a/pythoncms/static/themes/front/hyperspace/assets/css/images/intro.svg b/pythoncms/static/themes/front/hyperspace/assets/css/images/intro.svg new file mode 100644 index 0000000..a206ba3 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/css/images/intro.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/pythoncms/static/themes/front/hyperspace/assets/css/main.css b/pythoncms/static/themes/front/hyperspace/assets/css/main.css new file mode 100644 index 0000000..7622c59 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/css/main.css @@ -0,0 +1,3909 @@ +@import url(fontawesome-all.min.css); + +/* + Hyperspace by HTML5 UP + html5up.net | @ajlkn + Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +*/ + +html, body, div, span, applet, object, +iframe, h1, h2, h3, h4, h5, h6, p, blockquote, +pre, a, abbr, acronym, address, big, cite, +code, del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, b, +u, i, center, dl, dt, dd, ol, ul, li, fieldset, +form, label, legend, table, caption, tbody, +tfoot, thead, tr, th, td, article, aside, +canvas, details, embed, figure, figcaption, +footer, header, hgroup, menu, nav, output, ruby, +section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline;} + +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block;} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + + blockquote:before, blockquote:after, q:before, q:after { + content: ''; + content: none; + } + +table { + border-collapse: collapse; + border-spacing: 0; +} + +body { + -webkit-text-size-adjust: none; +} + +mark { + background-color: transparent; + color: inherit; +} + +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +input, select, textarea { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; +} + +/* Basic */ + + @-ms-viewport { + width: device-width; + } + + body { + -ms-overflow-style: scrollbar; + } + + @media screen and (max-width: 480px) { + + html, body { + min-width: 320px; + } + + } + + html { + box-sizing: border-box; + } + + *, *:before, *:after { + box-sizing: inherit; + } + + body { + background: #312450; + } + + body.is-preload *, body.is-preload *:before, body.is-preload *:after { + -moz-animation: none !important; + -webkit-animation: none !important; + -ms-animation: none !important; + animation: none !important; + -moz-transition: none !important; + -webkit-transition: none !important; + -ms-transition: none !important; + transition: none !important; + } + +/* Type */ + + body, input, select, textarea { + color: rgba(255, 255, 255, 0.55); + font-family: Arial, Helvetica, sans-serif; + font-size: 16.5pt; + font-weight: normal; + line-height: 1.75; + } + + @media screen and (max-width: 1680px) { + + body, input, select, textarea { + font-size: 13pt; + } + + } + + @media screen and (max-width: 1280px) { + + body, input, select, textarea { + font-size: 12pt; + } + + } + + @media screen and (max-width: 360px) { + + body, input, select, textarea { + font-size: 11pt; + } + + } + + a { + -moz-transition: color 0.2s ease, border-bottom-color 0.2s ease; + -webkit-transition: color 0.2s ease, border-bottom-color 0.2s ease; + -ms-transition: color 0.2s ease, border-bottom-color 0.2s ease; + transition: color 0.2s ease, border-bottom-color 0.2s ease; + border-bottom: dotted 1px rgba(255, 255, 255, 0.35); + color: inherit; + text-decoration: none; + } + + a:hover { + border-bottom-color: transparent; + color: #ffffff; + } + + strong, b { + color: #ffffff; + font-weight: bold; + } + + em, i { + font-style: italic; + } + + p { + margin: 0 0 2em 0; + } + + h1, h2, h3, h4, h5, h6 { + color: #ffffff; + font-weight: bold; + line-height: 1.5; + margin: 0 0 0.5em 0; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { + color: inherit; + text-decoration: none; + } + + h1 { + font-size: 2.75em; + } + + h1.major { + margin: 0 0 1.3em 0; + position: relative; + padding-bottom: 0.35em; + } + + h1.major:after { + background-image: -moz-linear-gradient(to right, #5e42a6, #b74e91); + background-image: -webkit-linear-gradient(to right, #5e42a6, #b74e91); + background-image: -ms-linear-gradient(to right, #5e42a6, #b74e91); + background-image: linear-gradient(to right, #5e42a6, #b74e91); + -moz-transition: max-width 0.2s ease; + -webkit-transition: max-width 0.2s ease; + -ms-transition: max-width 0.2s ease; + transition: max-width 0.2s ease; + border-radius: 0.2em; + bottom: 0; + content: ''; + height: 0.05em; + position: absolute; + right: 0; + width: 100%; + } + + h2 { + font-size: 1.75em; + } + + h3 { + font-size: 1.1em; + } + + h4 { + font-size: 1em; + } + + h5 { + font-size: 0.8em; + } + + h6 { + font-size: 0.6em; + } + + @media screen and (max-width: 736px) { + + h1 { + font-size: 2em; + } + + h2 { + font-size: 1.25em; + } + + h3 { + font-size: 1em; + } + + h4 { + font-size: 0.8em; + } + + h5 { + font-size: 0.6em; + } + + h6 { + font-size: 0.6em; + } + + } + + sub { + font-size: 0.8em; + position: relative; + top: 0.5em; + } + + sup { + font-size: 0.8em; + position: relative; + top: -0.5em; + } + + blockquote { + border-left: solid 4px rgba(255, 255, 255, 0.15); + font-style: italic; + margin: 0 0 2em 0; + padding: 0.5em 0 0.5em 2em; + } + + code { + background: rgba(255, 255, 255, 0.05); + border-radius: 0.25em; + border: solid 1px rgba(255, 255, 255, 0.15); + font-family: "Courier New", monospace; + font-size: 0.9em; + margin: 0 0.25em; + padding: 0.25em 0.65em; + } + + pre { + -webkit-overflow-scrolling: touch; + font-family: "Courier New", monospace; + font-size: 0.9em; + margin: 0 0 2em 0; + } + + pre code { + display: block; + line-height: 1.75em; + padding: 1em 1.5em; + overflow-x: auto; + } + + hr { + border: 0; + border-bottom: solid 1px rgba(255, 255, 255, 0.15); + margin: 2em 0; + } + + hr.major { + margin: 3em 0; + } + + .align-left { + text-align: left; + } + + .align-center { + text-align: center; + } + + .align-right { + text-align: right; + } + +/* Row */ + + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + } + + .row > * { + box-sizing: border-box; + } + + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; + } + + .row.aln-left { + justify-content: flex-start; + } + + .row.aln-center { + justify-content: center; + } + + .row.aln-right { + justify-content: flex-end; + } + + .row.aln-top { + align-items: flex-start; + } + + .row.aln-middle { + align-items: center; + } + + .row.aln-bottom { + align-items: flex-end; + } + + .row > .imp { + order: -1; + } + + .row > .col-1 { + width: 8.33333%; + } + + .row > .off-1 { + margin-left: 8.33333%; + } + + .row > .col-2 { + width: 16.66667%; + } + + .row > .off-2 { + margin-left: 16.66667%; + } + + .row > .col-3 { + width: 25%; + } + + .row > .off-3 { + margin-left: 25%; + } + + .row > .col-4 { + width: 33.33333%; + } + + .row > .off-4 { + margin-left: 33.33333%; + } + + .row > .col-5 { + width: 41.66667%; + } + + .row > .off-5 { + margin-left: 41.66667%; + } + + .row > .col-6 { + width: 50%; + } + + .row > .off-6 { + margin-left: 50%; + } + + .row > .col-7 { + width: 58.33333%; + } + + .row > .off-7 { + margin-left: 58.33333%; + } + + .row > .col-8 { + width: 66.66667%; + } + + .row > .off-8 { + margin-left: 66.66667%; + } + + .row > .col-9 { + width: 75%; + } + + .row > .off-9 { + margin-left: 75%; + } + + .row > .col-10 { + width: 83.33333%; + } + + .row > .off-10 { + margin-left: 83.33333%; + } + + .row > .col-11 { + width: 91.66667%; + } + + .row > .off-11 { + margin-left: 91.66667%; + } + + .row > .col-12 { + width: 100%; + } + + .row > .off-12 { + margin-left: 100%; + } + + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; + } + + .row.gtr-0 > * { + padding: 0 0 0 0em; + } + + .row.gtr-0.gtr-uniform { + margin-top: 0em; + } + + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; + } + + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; + } + + .row.gtr-25 > * { + padding: 0 0 0 0.375em; + } + + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; + } + + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; + } + + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; + } + + .row.gtr-50 > * { + padding: 0 0 0 0.75em; + } + + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; + } + + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; + } + + .row { + margin-top: 0; + margin-left: -1.5em; + } + + .row > * { + padding: 0 0 0 1.5em; + } + + .row.gtr-uniform { + margin-top: -1.5em; + } + + .row.gtr-uniform > * { + padding-top: 1.5em; + } + + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; + } + + .row.gtr-150 > * { + padding: 0 0 0 2.25em; + } + + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; + } + + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; + } + + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; + } + + .row.gtr-200 > * { + padding: 0 0 0 3em; + } + + .row.gtr-200.gtr-uniform { + margin-top: -3em; + } + + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; + } + + @media screen and (max-width: 1680px) { + + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + } + + .row > * { + box-sizing: border-box; + } + + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; + } + + .row.aln-left { + justify-content: flex-start; + } + + .row.aln-center { + justify-content: center; + } + + .row.aln-right { + justify-content: flex-end; + } + + .row.aln-top { + align-items: flex-start; + } + + .row.aln-middle { + align-items: center; + } + + .row.aln-bottom { + align-items: flex-end; + } + + .row > .imp-xlarge { + order: -1; + } + + .row > .col-1-xlarge { + width: 8.33333%; + } + + .row > .off-1-xlarge { + margin-left: 8.33333%; + } + + .row > .col-2-xlarge { + width: 16.66667%; + } + + .row > .off-2-xlarge { + margin-left: 16.66667%; + } + + .row > .col-3-xlarge { + width: 25%; + } + + .row > .off-3-xlarge { + margin-left: 25%; + } + + .row > .col-4-xlarge { + width: 33.33333%; + } + + .row > .off-4-xlarge { + margin-left: 33.33333%; + } + + .row > .col-5-xlarge { + width: 41.66667%; + } + + .row > .off-5-xlarge { + margin-left: 41.66667%; + } + + .row > .col-6-xlarge { + width: 50%; + } + + .row > .off-6-xlarge { + margin-left: 50%; + } + + .row > .col-7-xlarge { + width: 58.33333%; + } + + .row > .off-7-xlarge { + margin-left: 58.33333%; + } + + .row > .col-8-xlarge { + width: 66.66667%; + } + + .row > .off-8-xlarge { + margin-left: 66.66667%; + } + + .row > .col-9-xlarge { + width: 75%; + } + + .row > .off-9-xlarge { + margin-left: 75%; + } + + .row > .col-10-xlarge { + width: 83.33333%; + } + + .row > .off-10-xlarge { + margin-left: 83.33333%; + } + + .row > .col-11-xlarge { + width: 91.66667%; + } + + .row > .off-11-xlarge { + margin-left: 91.66667%; + } + + .row > .col-12-xlarge { + width: 100%; + } + + .row > .off-12-xlarge { + margin-left: 100%; + } + + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; + } + + .row.gtr-0 > * { + padding: 0 0 0 0em; + } + + .row.gtr-0.gtr-uniform { + margin-top: 0em; + } + + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; + } + + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; + } + + .row.gtr-25 > * { + padding: 0 0 0 0.375em; + } + + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; + } + + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; + } + + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; + } + + .row.gtr-50 > * { + padding: 0 0 0 0.75em; + } + + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; + } + + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; + } + + .row { + margin-top: 0; + margin-left: -1.5em; + } + + .row > * { + padding: 0 0 0 1.5em; + } + + .row.gtr-uniform { + margin-top: -1.5em; + } + + .row.gtr-uniform > * { + padding-top: 1.5em; + } + + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; + } + + .row.gtr-150 > * { + padding: 0 0 0 2.25em; + } + + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; + } + + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; + } + + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; + } + + .row.gtr-200 > * { + padding: 0 0 0 3em; + } + + .row.gtr-200.gtr-uniform { + margin-top: -3em; + } + + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; + } + + } + + @media screen and (max-width: 1280px) { + + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + } + + .row > * { + box-sizing: border-box; + } + + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; + } + + .row.aln-left { + justify-content: flex-start; + } + + .row.aln-center { + justify-content: center; + } + + .row.aln-right { + justify-content: flex-end; + } + + .row.aln-top { + align-items: flex-start; + } + + .row.aln-middle { + align-items: center; + } + + .row.aln-bottom { + align-items: flex-end; + } + + .row > .imp-large { + order: -1; + } + + .row > .col-1-large { + width: 8.33333%; + } + + .row > .off-1-large { + margin-left: 8.33333%; + } + + .row > .col-2-large { + width: 16.66667%; + } + + .row > .off-2-large { + margin-left: 16.66667%; + } + + .row > .col-3-large { + width: 25%; + } + + .row > .off-3-large { + margin-left: 25%; + } + + .row > .col-4-large { + width: 33.33333%; + } + + .row > .off-4-large { + margin-left: 33.33333%; + } + + .row > .col-5-large { + width: 41.66667%; + } + + .row > .off-5-large { + margin-left: 41.66667%; + } + + .row > .col-6-large { + width: 50%; + } + + .row > .off-6-large { + margin-left: 50%; + } + + .row > .col-7-large { + width: 58.33333%; + } + + .row > .off-7-large { + margin-left: 58.33333%; + } + + .row > .col-8-large { + width: 66.66667%; + } + + .row > .off-8-large { + margin-left: 66.66667%; + } + + .row > .col-9-large { + width: 75%; + } + + .row > .off-9-large { + margin-left: 75%; + } + + .row > .col-10-large { + width: 83.33333%; + } + + .row > .off-10-large { + margin-left: 83.33333%; + } + + .row > .col-11-large { + width: 91.66667%; + } + + .row > .off-11-large { + margin-left: 91.66667%; + } + + .row > .col-12-large { + width: 100%; + } + + .row > .off-12-large { + margin-left: 100%; + } + + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; + } + + .row.gtr-0 > * { + padding: 0 0 0 0em; + } + + .row.gtr-0.gtr-uniform { + margin-top: 0em; + } + + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; + } + + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; + } + + .row.gtr-25 > * { + padding: 0 0 0 0.375em; + } + + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; + } + + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; + } + + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; + } + + .row.gtr-50 > * { + padding: 0 0 0 0.75em; + } + + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; + } + + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; + } + + .row { + margin-top: 0; + margin-left: -1.5em; + } + + .row > * { + padding: 0 0 0 1.5em; + } + + .row.gtr-uniform { + margin-top: -1.5em; + } + + .row.gtr-uniform > * { + padding-top: 1.5em; + } + + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; + } + + .row.gtr-150 > * { + padding: 0 0 0 2.25em; + } + + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; + } + + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; + } + + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; + } + + .row.gtr-200 > * { + padding: 0 0 0 3em; + } + + .row.gtr-200.gtr-uniform { + margin-top: -3em; + } + + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; + } + + } + + @media screen and (max-width: 980px) { + + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + } + + .row > * { + box-sizing: border-box; + } + + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; + } + + .row.aln-left { + justify-content: flex-start; + } + + .row.aln-center { + justify-content: center; + } + + .row.aln-right { + justify-content: flex-end; + } + + .row.aln-top { + align-items: flex-start; + } + + .row.aln-middle { + align-items: center; + } + + .row.aln-bottom { + align-items: flex-end; + } + + .row > .imp-medium { + order: -1; + } + + .row > .col-1-medium { + width: 8.33333%; + } + + .row > .off-1-medium { + margin-left: 8.33333%; + } + + .row > .col-2-medium { + width: 16.66667%; + } + + .row > .off-2-medium { + margin-left: 16.66667%; + } + + .row > .col-3-medium { + width: 25%; + } + + .row > .off-3-medium { + margin-left: 25%; + } + + .row > .col-4-medium { + width: 33.33333%; + } + + .row > .off-4-medium { + margin-left: 33.33333%; + } + + .row > .col-5-medium { + width: 41.66667%; + } + + .row > .off-5-medium { + margin-left: 41.66667%; + } + + .row > .col-6-medium { + width: 50%; + } + + .row > .off-6-medium { + margin-left: 50%; + } + + .row > .col-7-medium { + width: 58.33333%; + } + + .row > .off-7-medium { + margin-left: 58.33333%; + } + + .row > .col-8-medium { + width: 66.66667%; + } + + .row > .off-8-medium { + margin-left: 66.66667%; + } + + .row > .col-9-medium { + width: 75%; + } + + .row > .off-9-medium { + margin-left: 75%; + } + + .row > .col-10-medium { + width: 83.33333%; + } + + .row > .off-10-medium { + margin-left: 83.33333%; + } + + .row > .col-11-medium { + width: 91.66667%; + } + + .row > .off-11-medium { + margin-left: 91.66667%; + } + + .row > .col-12-medium { + width: 100%; + } + + .row > .off-12-medium { + margin-left: 100%; + } + + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; + } + + .row.gtr-0 > * { + padding: 0 0 0 0em; + } + + .row.gtr-0.gtr-uniform { + margin-top: 0em; + } + + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; + } + + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; + } + + .row.gtr-25 > * { + padding: 0 0 0 0.375em; + } + + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; + } + + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; + } + + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; + } + + .row.gtr-50 > * { + padding: 0 0 0 0.75em; + } + + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; + } + + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; + } + + .row { + margin-top: 0; + margin-left: -1.5em; + } + + .row > * { + padding: 0 0 0 1.5em; + } + + .row.gtr-uniform { + margin-top: -1.5em; + } + + .row.gtr-uniform > * { + padding-top: 1.5em; + } + + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; + } + + .row.gtr-150 > * { + padding: 0 0 0 2.25em; + } + + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; + } + + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; + } + + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; + } + + .row.gtr-200 > * { + padding: 0 0 0 3em; + } + + .row.gtr-200.gtr-uniform { + margin-top: -3em; + } + + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; + } + + } + + @media screen and (max-width: 736px) { + + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + } + + .row > * { + box-sizing: border-box; + } + + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; + } + + .row.aln-left { + justify-content: flex-start; + } + + .row.aln-center { + justify-content: center; + } + + .row.aln-right { + justify-content: flex-end; + } + + .row.aln-top { + align-items: flex-start; + } + + .row.aln-middle { + align-items: center; + } + + .row.aln-bottom { + align-items: flex-end; + } + + .row > .imp-small { + order: -1; + } + + .row > .col-1-small { + width: 8.33333%; + } + + .row > .off-1-small { + margin-left: 8.33333%; + } + + .row > .col-2-small { + width: 16.66667%; + } + + .row > .off-2-small { + margin-left: 16.66667%; + } + + .row > .col-3-small { + width: 25%; + } + + .row > .off-3-small { + margin-left: 25%; + } + + .row > .col-4-small { + width: 33.33333%; + } + + .row > .off-4-small { + margin-left: 33.33333%; + } + + .row > .col-5-small { + width: 41.66667%; + } + + .row > .off-5-small { + margin-left: 41.66667%; + } + + .row > .col-6-small { + width: 50%; + } + + .row > .off-6-small { + margin-left: 50%; + } + + .row > .col-7-small { + width: 58.33333%; + } + + .row > .off-7-small { + margin-left: 58.33333%; + } + + .row > .col-8-small { + width: 66.66667%; + } + + .row > .off-8-small { + margin-left: 66.66667%; + } + + .row > .col-9-small { + width: 75%; + } + + .row > .off-9-small { + margin-left: 75%; + } + + .row > .col-10-small { + width: 83.33333%; + } + + .row > .off-10-small { + margin-left: 83.33333%; + } + + .row > .col-11-small { + width: 91.66667%; + } + + .row > .off-11-small { + margin-left: 91.66667%; + } + + .row > .col-12-small { + width: 100%; + } + + .row > .off-12-small { + margin-left: 100%; + } + + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; + } + + .row.gtr-0 > * { + padding: 0 0 0 0em; + } + + .row.gtr-0.gtr-uniform { + margin-top: 0em; + } + + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; + } + + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; + } + + .row.gtr-25 > * { + padding: 0 0 0 0.375em; + } + + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; + } + + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; + } + + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; + } + + .row.gtr-50 > * { + padding: 0 0 0 0.75em; + } + + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; + } + + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; + } + + .row { + margin-top: 0; + margin-left: -1.5em; + } + + .row > * { + padding: 0 0 0 1.5em; + } + + .row.gtr-uniform { + margin-top: -1.5em; + } + + .row.gtr-uniform > * { + padding-top: 1.5em; + } + + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; + } + + .row.gtr-150 > * { + padding: 0 0 0 2.25em; + } + + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; + } + + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; + } + + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; + } + + .row.gtr-200 > * { + padding: 0 0 0 3em; + } + + .row.gtr-200.gtr-uniform { + margin-top: -3em; + } + + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; + } + + } + + @media screen and (max-width: 480px) { + + .row { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + } + + .row > * { + box-sizing: border-box; + } + + .row.gtr-uniform > * > :last-child { + margin-bottom: 0; + } + + .row.aln-left { + justify-content: flex-start; + } + + .row.aln-center { + justify-content: center; + } + + .row.aln-right { + justify-content: flex-end; + } + + .row.aln-top { + align-items: flex-start; + } + + .row.aln-middle { + align-items: center; + } + + .row.aln-bottom { + align-items: flex-end; + } + + .row > .imp-xsmall { + order: -1; + } + + .row > .col-1-xsmall { + width: 8.33333%; + } + + .row > .off-1-xsmall { + margin-left: 8.33333%; + } + + .row > .col-2-xsmall { + width: 16.66667%; + } + + .row > .off-2-xsmall { + margin-left: 16.66667%; + } + + .row > .col-3-xsmall { + width: 25%; + } + + .row > .off-3-xsmall { + margin-left: 25%; + } + + .row > .col-4-xsmall { + width: 33.33333%; + } + + .row > .off-4-xsmall { + margin-left: 33.33333%; + } + + .row > .col-5-xsmall { + width: 41.66667%; + } + + .row > .off-5-xsmall { + margin-left: 41.66667%; + } + + .row > .col-6-xsmall { + width: 50%; + } + + .row > .off-6-xsmall { + margin-left: 50%; + } + + .row > .col-7-xsmall { + width: 58.33333%; + } + + .row > .off-7-xsmall { + margin-left: 58.33333%; + } + + .row > .col-8-xsmall { + width: 66.66667%; + } + + .row > .off-8-xsmall { + margin-left: 66.66667%; + } + + .row > .col-9-xsmall { + width: 75%; + } + + .row > .off-9-xsmall { + margin-left: 75%; + } + + .row > .col-10-xsmall { + width: 83.33333%; + } + + .row > .off-10-xsmall { + margin-left: 83.33333%; + } + + .row > .col-11-xsmall { + width: 91.66667%; + } + + .row > .off-11-xsmall { + margin-left: 91.66667%; + } + + .row > .col-12-xsmall { + width: 100%; + } + + .row > .off-12-xsmall { + margin-left: 100%; + } + + .row.gtr-0 { + margin-top: 0; + margin-left: 0em; + } + + .row.gtr-0 > * { + padding: 0 0 0 0em; + } + + .row.gtr-0.gtr-uniform { + margin-top: 0em; + } + + .row.gtr-0.gtr-uniform > * { + padding-top: 0em; + } + + .row.gtr-25 { + margin-top: 0; + margin-left: -0.375em; + } + + .row.gtr-25 > * { + padding: 0 0 0 0.375em; + } + + .row.gtr-25.gtr-uniform { + margin-top: -0.375em; + } + + .row.gtr-25.gtr-uniform > * { + padding-top: 0.375em; + } + + .row.gtr-50 { + margin-top: 0; + margin-left: -0.75em; + } + + .row.gtr-50 > * { + padding: 0 0 0 0.75em; + } + + .row.gtr-50.gtr-uniform { + margin-top: -0.75em; + } + + .row.gtr-50.gtr-uniform > * { + padding-top: 0.75em; + } + + .row { + margin-top: 0; + margin-left: -1.5em; + } + + .row > * { + padding: 0 0 0 1.5em; + } + + .row.gtr-uniform { + margin-top: -1.5em; + } + + .row.gtr-uniform > * { + padding-top: 1.5em; + } + + .row.gtr-150 { + margin-top: 0; + margin-left: -2.25em; + } + + .row.gtr-150 > * { + padding: 0 0 0 2.25em; + } + + .row.gtr-150.gtr-uniform { + margin-top: -2.25em; + } + + .row.gtr-150.gtr-uniform > * { + padding-top: 2.25em; + } + + .row.gtr-200 { + margin-top: 0; + margin-left: -3em; + } + + .row.gtr-200 > * { + padding: 0 0 0 3em; + } + + .row.gtr-200.gtr-uniform { + margin-top: -3em; + } + + .row.gtr-200.gtr-uniform > * { + padding-top: 3em; + } + + } + +/* Box */ + + .box { + border-radius: 0.25em; + border: solid 1px rgba(255, 255, 255, 0.15); + margin-bottom: 2em; + padding: 1.5em; + } + + .box > :last-child, + .box > :last-child > :last-child, + .box > :last-child > :last-child > :last-child { + margin-bottom: 0; + } + + .box.alt { + border: 0; + border-radius: 0; + padding: 0; + } + +/* Button */ + + input[type="submit"], + input[type="reset"], + input[type="button"], + button, + .button { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + -moz-transition: border-color 0.2s ease; + -webkit-transition: border-color 0.2s ease; + -ms-transition: border-color 0.2s ease; + transition: border-color 0.2s ease; + background-color: transparent; + border: solid 1px !important; + border-color: rgba(255, 255, 255, 0.15) !important; + border-radius: 3em; + color: #ffffff !important; + cursor: pointer; + display: inline-block; + font-size: 0.6em; + font-weight: bold; + height: calc(4.75em + 2px); + letter-spacing: 0.25em; + line-height: 4.75em; + outline: 0; + padding: 0 3.75em; + position: relative; + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + } + + input[type="submit"]:after, + input[type="reset"]:after, + input[type="button"]:after, + button:after, + .button:after { + -moz-transform: scale(0.25); + -webkit-transform: scale(0.25); + -ms-transform: scale(0.25); + transform: scale(0.25); + pointer-events: none; + -moz-transition: opacity 0.2s ease, -moz-transform 0.2s ease; + -webkit-transition: opacity 0.2s ease, -webkit-transform 0.2s ease; + -ms-transition: opacity 0.2s ease, -ms-transform 0.2s ease; + transition: opacity 0.2s ease, transform 0.2s ease; + background: #ffffff; + border-radius: 3em; + content: ''; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + } + + input[type="submit"].icon:before, + input[type="reset"].icon:before, + input[type="button"].icon:before, + button.icon:before, + .button.icon:before { + margin-right: 0.75em; + } + + input[type="submit"].fit, + input[type="reset"].fit, + input[type="button"].fit, + button.fit, + .button.fit { + width: 100%; + } + + input[type="submit"].small, + input[type="reset"].small, + input[type="button"].small, + button.small, + .button.small { + font-size: 0.4em; + } + + input[type="submit"].large, + input[type="reset"].large, + input[type="button"].large, + button.large, + .button.large { + font-size: 0.8em; + } + + input[type="submit"].primary, + input[type="reset"].primary, + input[type="button"].primary, + button.primary, + .button.primary { + background-color: #ffffff; + color: #312450 !important; + } + + input[type="submit"].primary:after, + input[type="reset"].primary:after, + input[type="button"].primary:after, + button.primary:after, + .button.primary:after { + display: none; + } + + input[type="submit"].disabled, input[type="submit"]:disabled, + input[type="reset"].disabled, + input[type="reset"]:disabled, + input[type="button"].disabled, + input[type="button"]:disabled, + button.disabled, + button:disabled, + .button.disabled, + .button:disabled { + cursor: default; + opacity: 0.5; + pointer-events: none; + } + + input[type="submit"]:hover, + input[type="reset"]:hover, + input[type="button"]:hover, + button:hover, + .button:hover { + border-color: rgba(255, 255, 255, 0.55) !important; + } + + input[type="submit"]:hover:after, + input[type="reset"]:hover:after, + input[type="button"]:hover:after, + button:hover:after, + .button:hover:after { + opacity: 0.05; + -moz-transform: scale(1); + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + + input[type="submit"]:hover:active, + input[type="reset"]:hover:active, + input[type="button"]:hover:active, + button:hover:active, + .button:hover:active { + border-color: #ffffff !important; + } + + input[type="submit"]:hover:active:after, + input[type="reset"]:hover:active:after, + input[type="button"]:hover:active:after, + button:hover:active:after, + .button:hover:active:after { + opacity: 0.1; + } + +/* Features */ + + .features { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + border-radius: 0.25em; + border: solid 1px rgba(255, 255, 255, 0.15); + background: rgba(255, 255, 255, 0.05); + margin: 0 0 2em 0; + } + + .features section { + padding: 3.5em 3em 1em 7em ; + width: 50%; + border-top: solid 1px rgba(255, 255, 255, 0.15); + position: relative; + } + + .features section:nth-child(-n + 2) { + border-top-width: 0; + } + + .features section:nth-child(2n) { + border-left: solid 1px rgba(255, 255, 255, 0.15); + } + + .features section .icon { + -moz-transition: opacity 0.5s ease, -moz-transform 0.5s ease; + -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + -ms-transition: opacity 0.5s ease, -ms-transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease; + -moz-transition-delay: 1s; + -webkit-transition-delay: 1s; + -ms-transition-delay: 1s; + transition-delay: 1s; + -moz-transform: scale(1); + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + position: absolute; + left: 3em; + top: 3em; + opacity: 1; + } + + .features section:nth-child(1) .icon { + -moz-transition-delay: 0.15s; + -webkit-transition-delay: 0.15s; + -ms-transition-delay: 0.15s; + transition-delay: 0.15s; + } + + .features section:nth-child(2) .icon { + -moz-transition-delay: 0.3s; + -webkit-transition-delay: 0.3s; + -ms-transition-delay: 0.3s; + transition-delay: 0.3s; + } + + .features section:nth-child(3) .icon { + -moz-transition-delay: 0.45s; + -webkit-transition-delay: 0.45s; + -ms-transition-delay: 0.45s; + transition-delay: 0.45s; + } + + .features section:nth-child(4) .icon { + -moz-transition-delay: 0.6s; + -webkit-transition-delay: 0.6s; + -ms-transition-delay: 0.6s; + transition-delay: 0.6s; + } + + .features section:nth-child(5) .icon { + -moz-transition-delay: 0.75s; + -webkit-transition-delay: 0.75s; + -ms-transition-delay: 0.75s; + transition-delay: 0.75s; + } + + .features section:nth-child(6) .icon { + -moz-transition-delay: 0.9s; + -webkit-transition-delay: 0.9s; + -ms-transition-delay: 0.9s; + transition-delay: 0.9s; + } + + .features section:nth-child(7) .icon { + -moz-transition-delay: 1.05s; + -webkit-transition-delay: 1.05s; + -ms-transition-delay: 1.05s; + transition-delay: 1.05s; + } + + .features section:nth-child(8) .icon { + -moz-transition-delay: 1.2s; + -webkit-transition-delay: 1.2s; + -ms-transition-delay: 1.2s; + transition-delay: 1.2s; + } + + .features section:nth-child(9) .icon { + -moz-transition-delay: 1.35s; + -webkit-transition-delay: 1.35s; + -ms-transition-delay: 1.35s; + transition-delay: 1.35s; + } + + .features section:nth-child(10) .icon { + -moz-transition-delay: 1.5s; + -webkit-transition-delay: 1.5s; + -ms-transition-delay: 1.5s; + transition-delay: 1.5s; + } + + .features section:nth-child(11) .icon { + -moz-transition-delay: 1.65s; + -webkit-transition-delay: 1.65s; + -ms-transition-delay: 1.65s; + transition-delay: 1.65s; + } + + .features section:nth-child(12) .icon { + -moz-transition-delay: 1.8s; + -webkit-transition-delay: 1.8s; + -ms-transition-delay: 1.8s; + transition-delay: 1.8s; + } + + .features section:nth-child(13) .icon { + -moz-transition-delay: 1.95s; + -webkit-transition-delay: 1.95s; + -ms-transition-delay: 1.95s; + transition-delay: 1.95s; + } + + .features section:nth-child(14) .icon { + -moz-transition-delay: 2.1s; + -webkit-transition-delay: 2.1s; + -ms-transition-delay: 2.1s; + transition-delay: 2.1s; + } + + .features section:nth-child(15) .icon { + -moz-transition-delay: 2.25s; + -webkit-transition-delay: 2.25s; + -ms-transition-delay: 2.25s; + transition-delay: 2.25s; + } + + .features section:nth-child(16) .icon { + -moz-transition-delay: 2.4s; + -webkit-transition-delay: 2.4s; + -ms-transition-delay: 2.4s; + transition-delay: 2.4s; + } + + .features section:nth-child(17) .icon { + -moz-transition-delay: 2.55s; + -webkit-transition-delay: 2.55s; + -ms-transition-delay: 2.55s; + transition-delay: 2.55s; + } + + .features section:nth-child(18) .icon { + -moz-transition-delay: 2.7s; + -webkit-transition-delay: 2.7s; + -ms-transition-delay: 2.7s; + transition-delay: 2.7s; + } + + .features section:nth-child(19) .icon { + -moz-transition-delay: 2.85s; + -webkit-transition-delay: 2.85s; + -ms-transition-delay: 2.85s; + transition-delay: 2.85s; + } + + .features section:nth-child(20) .icon { + -moz-transition-delay: 3s; + -webkit-transition-delay: 3s; + -ms-transition-delay: 3s; + transition-delay: 3s; + } + + .features.inactive section .icon { + -moz-transform: scale(0.5); + -webkit-transform: scale(0.5); + -ms-transform: scale(0.5); + transform: scale(0.5); + opacity: 0; + } + + @media screen and (max-width: 980px) { + + .features { + display: block; + } + + .features section { + border-top-width: 1px !important; + border-left-width: 0 !important; + width: 100%; + } + + .features section:first-child { + border-top-width: 0 !important; + } + + } + + @media screen and (max-width: 736px) { + + .features section { + padding: 2.5em 1.5em 0.1em 5.5em ; + } + + .features section .icon { + left: 1.5em; + top: 2em; + } + + } + + @media screen and (max-width: 480px) { + + .features section { + padding: 2em 1.5em 0.1em 1.5em ; + } + + .features section .icon { + left: 0; + position: relative; + top: 0; + } + + } + +/* Form */ + + form { + margin: 0 0 2em 0; + } + + form > :last-child { + margin-bottom: 0; + } + + form > .fields { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + width: calc(100% + 3em); + margin: -1.5em 0 2em -1.5em; + } + + form > .fields > .field { + -moz-flex-grow: 0; + -webkit-flex-grow: 0; + -ms-flex-grow: 0; + flex-grow: 0; + -moz-flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex-shrink: 0; + flex-shrink: 0; + padding: 1.5em 0 0 1.5em; + width: calc(100% - 1.5em); + } + + form > .fields > .field.half { + width: calc(50% - 0.75em); + } + + form > .fields > .field.third { + width: calc(100%/3 - 0.5em); + } + + form > .fields > .field.quarter { + width: calc(25% - 0.375em); + } + + @media screen and (max-width: 480px) { + + form > .fields { + width: calc(100% + 3em); + margin: -1.5em 0 2em -1.5em; + } + + form > .fields > .field { + padding: 1.5em 0 0 1.5em; + width: calc(100% - 1.5em); + } + + form > .fields > .field.half { + width: calc(100% - 1.5em); + } + + form > .fields > .field.third { + width: calc(100% - 1.5em); + } + + form > .fields > .field.quarter { + width: calc(100% - 1.5em); + } + + } + + label { + color: #ffffff; + font-weight: bold; + line-height: 1.5; + margin: 0 0 0.7em 0; + display: block; + font-size: 1.1em; + } + + input[type="text"], + input[type="password"], + input[type="email"], + input[type="tel"], + select, + textarea { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + background: rgba(255, 255, 255, 0.05); + border-radius: 0.25em; + border: none; + border: solid 1px rgba(255, 255, 255, 0.15); + color: inherit; + display: block; + outline: 0; + padding: 0 1em; + text-decoration: none; + width: 100%; + } + + input[type="text"]:invalid, + input[type="password"]:invalid, + input[type="email"]:invalid, + input[type="tel"]:invalid, + select:invalid, + textarea:invalid { + box-shadow: none; + } + + input[type="text"]:focus, + input[type="password"]:focus, + input[type="email"]:focus, + input[type="tel"]:focus, + select:focus, + textarea:focus { + border-color: #ffffff; + box-shadow: 0 0 0 1px #ffffff; + } + + select { + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' preserveAspectRatio='none' viewBox='0 0 40 40'%3E%3Cpath d='M9.4,12.3l10.4,10.4l10.4-10.4c0.2-0.2,0.5-0.4,0.9-0.4c0.3,0,0.6,0.1,0.9,0.4l3.3,3.3c0.2,0.2,0.4,0.5,0.4,0.9 c0,0.4-0.1,0.6-0.4,0.9L20.7,31.9c-0.2,0.2-0.5,0.4-0.9,0.4c-0.3,0-0.6-0.1-0.9-0.4L4.3,17.3c-0.2-0.2-0.4-0.5-0.4-0.9 c0-0.4,0.1-0.6,0.4-0.9l3.3-3.3c0.2-0.2,0.5-0.4,0.9-0.4S9.1,12.1,9.4,12.3z' fill='rgba(255, 255, 255, 0.15)' /%3E%3C/svg%3E"); + background-size: 1.25rem; + background-repeat: no-repeat; + background-position: calc(100% - 1rem) center; + height: 2.75em; + padding-right: 2.75em; + text-overflow: ellipsis; + } + + select option { + color: #ffffff; + background: #312450; + } + + select:focus::-ms-value { + background-color: transparent; + } + + select::-ms-expand { + display: none; + } + + input[type="text"], + input[type="password"], + input[type="email"], + select { + height: 2.75em; + } + + textarea { + padding: 0.75em 1em; + } + + body.is-ie textarea { + min-height: 10em; + } + + input[type="checkbox"], + input[type="radio"] { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + display: block; + float: left; + margin-right: -2em; + opacity: 0; + width: 1em; + z-index: -1; + } + + input[type="checkbox"] + label, + input[type="radio"] + label { + text-decoration: none; + color: rgba(255, 255, 255, 0.55); + cursor: pointer; + display: inline-block; + font-size: 1em; + font-weight: normal; + padding-left: 2.4em; + padding-right: 0.75em; + position: relative; + } + + input[type="checkbox"] + label:before, + input[type="radio"] + label:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 900; + } + + input[type="checkbox"] + label:before, + input[type="radio"] + label:before { + background: rgba(255, 255, 255, 0.05); + border-radius: 0.25em; + border: solid 1px rgba(255, 255, 255, 0.15); + content: ''; + display: inline-block; + font-size: 0.8em; + height: 2.0625em; + left: 0; + line-height: 2.0625em; + position: absolute; + text-align: center; + top: 0; + width: 2.0625em; + } + + input[type="checkbox"]:checked + label:before, + input[type="radio"]:checked + label:before { + background: #ffffff; + border-color: #ffffff; + color: #b74e91; + content: '\f00c'; + } + + input[type="checkbox"]:focus + label:before, + input[type="radio"]:focus + label:before { + border-color: #ffffff; + box-shadow: 0 0 0 1px #ffffff; + } + + input[type="checkbox"] + label:before { + border-radius: 0.25em; + } + + input[type="radio"] + label:before { + border-radius: 100%; + } + + ::-webkit-input-placeholder { + color: rgba(255, 255, 255, 0.35) !important; + opacity: 1.0; + } + + :-moz-placeholder { + color: rgba(255, 255, 255, 0.35) !important; + opacity: 1.0; + } + + ::-moz-placeholder { + color: rgba(255, 255, 255, 0.35) !important; + opacity: 1.0; + } + + :-ms-input-placeholder { + color: rgba(255, 255, 255, 0.35) !important; + opacity: 1.0; + } + +/* Icon */ + + .icon { + text-decoration: none; + border-bottom: none; + position: relative; + } + + .icon:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + font-family: 'Font Awesome 5 Free'; + font-weight: 400; + } + + .icon > .label { + display: none; + } + + .icon:before { + line-height: inherit; + } + + .icon.solid:before { + font-weight: 900; + } + + .icon.brands:before { + font-family: 'Font Awesome 5 Brands'; + } + + .icon.major { + width: 2.5em; + height: 2.5em; + display: block; + background: #ffffff; + border-radius: 100%; + color: #312450; + text-align: center; + line-height: 2.5em; + margin: 0 0 1.3em 0; + } + + .icon.major:before { + font-size: 1.25em; + } + + .wrapper.style1 .icon.major:before { + color: #5e42a6; + } + + .wrapper.style1-alt .icon.major:before { + color: #493382; + } + + .wrapper.style2 .icon.major:before { + color: #5052b5; + } + + .wrapper.style2-alt .icon.major:before { + color: #3e4094; + } + + .wrapper.style3 .icon.major:before { + color: #b74e91; + } + + .wrapper.style3-alt .icon.major:before { + color: #953d75; + } + +/* Image */ + + .image { + border-radius: 0.25em; + border: 0; + display: inline-block; + position: relative; + } + + .image img { + border-radius: 0.25em; + display: block; + } + + .image.left, .image.right { + max-width: 40%; + } + + .image.left img, .image.right img { + width: 100%; + } + + .image.left { + float: left; + margin: 0 1.5em 1em 0; + top: 0.25em; + } + + .image.right { + float: right; + margin: 0 0 1em 1.5em; + top: 0.25em; + } + + .image.fit { + display: block; + margin: 0 0 2em 0; + width: 100%; + } + + .image.fit img { + width: 100%; + } + + .image.main { + display: block; + margin: 0 0 3em 0; + width: 100%; + } + + .image.main img { + width: 100%; + } + +/* List */ + + ol { + list-style: decimal; + margin: 0 0 2em 0; + padding-left: 1.25em; + } + + ol li { + padding-left: 0.25em; + } + + ul { + list-style: disc; + margin: 0 0 2em 0; + padding-left: 1em; + } + + ul li { + padding-left: 0.5em; + } + + ul.alt { + list-style: none; + padding-left: 0; + } + + ul.alt li { + border-top: solid 1px rgba(255, 255, 255, 0.15); + padding: 0.5em 0; + } + + ul.alt li:first-child { + border-top: 0; + padding-top: 0; + } + + dl { + margin: 0 0 2em 0; + } + + dl dt { + display: block; + font-weight: bold; + margin: 0 0 1em 0; + } + + dl dd { + margin-left: 2em; + } + +/* Actions */ + + ul.actions { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + cursor: default; + list-style: none; + margin-left: -1em; + padding-left: 0; + } + + ul.actions li { + padding: 0 0 0 1em; + vertical-align: middle; + } + + ul.actions.special { + -moz-justify-content: center; + -webkit-justify-content: center; + -ms-justify-content: center; + justify-content: center; + width: 100%; + margin-left: 0; + } + + ul.actions.special li:first-child { + padding-left: 0; + } + + ul.actions.stacked { + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + margin-left: 0; + } + + ul.actions.stacked li { + padding: 1.3em 0 0 0; + } + + ul.actions.stacked li:first-child { + padding-top: 0; + } + + ul.actions.fit { + width: calc(100% + 1em); + } + + ul.actions.fit li { + -moz-flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex-grow: 1; + flex-grow: 1; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + width: 100%; + } + + ul.actions.fit li > * { + width: 100%; + } + + ul.actions.fit.stacked { + width: 100%; + } + + @media screen and (max-width: 480px) { + + ul.actions:not(.fixed) { + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + margin-left: 0; + width: 100% !important; + } + + ul.actions:not(.fixed) li { + -moz-flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex-grow: 1; + flex-grow: 1; + -moz-flex-shrink: 1; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + flex-shrink: 1; + padding: 1em 0 0 0; + text-align: center; + width: 100%; + } + + ul.actions:not(.fixed) li > * { + width: 100%; + } + + ul.actions:not(.fixed) li:first-child { + padding-top: 0; + } + + ul.actions:not(.fixed) li input[type="submit"], + ul.actions:not(.fixed) li input[type="reset"], + ul.actions:not(.fixed) li input[type="button"], + ul.actions:not(.fixed) li button, + ul.actions:not(.fixed) li .button { + width: 100%; + } + + ul.actions:not(.fixed) li input[type="submit"].icon:before, + ul.actions:not(.fixed) li input[type="reset"].icon:before, + ul.actions:not(.fixed) li input[type="button"].icon:before, + ul.actions:not(.fixed) li button.icon:before, + ul.actions:not(.fixed) li .button.icon:before { + margin-left: -0.5rem; + } + + } + +/* Contact */ + + ul.contact { + list-style: none; + padding: 0; + } + + ul.contact > li { + padding: 0; + margin: 1.5em 0 0 0; + } + + ul.contact > li:first-child { + margin-top: 0; + } + +/* Icons */ + + ul.icons { + cursor: default; + list-style: none; + padding-left: 0; + } + + ul.icons li { + display: inline-block; + padding: 0 0.75em 0 0; + } + + ul.icons li:last-child { + padding-right: 0; + } + + ul.icons li > a, ul.icons li > span { + border: 0; + } + + ul.icons li > a .label, ul.icons li > span .label { + display: none; + } + +/* Menu */ + + ul.menu { + list-style: none; + padding: 0; + } + + ul.menu > li { + border-left: solid 1px rgba(255, 255, 255, 0.15); + display: inline-block; + line-height: 1; + margin-left: 1.5em; + padding: 0 0 0 1.5em; + } + + ul.menu > li:first-child { + border-left: 0; + margin: 0; + padding-left: 0; + } + + @media screen and (max-width: 480px) { + + ul.menu > li { + border-left: 0; + display: block; + line-height: inherit; + margin: 0.5em 0 0 0; + padding-left: 0; + } + + } + +/* Section/Article */ + + section.special, article.special { + text-align: center; + } + + header p { + color: rgba(255, 255, 255, 0.35); + position: relative; + margin: 0 0 1.5em 0; + } + + header h2 + p { + font-size: 1.25em; + margin-top: -1em; + line-height: 1.5em; + } + + header h3 + p { + font-size: 1.1em; + margin-top: -0.8em; + line-height: 1.5em; + } + + header h4 + p, + header h5 + p, + header h6 + p { + font-size: 0.9em; + margin-top: -0.6em; + line-height: 1.5em; + } + +/* Split */ + + .split { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + } + + .split > * { + width: calc(50% - 2.5em); + } + + .split > :nth-child(2n - 1) { + padding-right: 2.5em; + border-right: solid 1px rgba(255, 255, 255, 0.15); + } + + .split > :nth-child(2n) { + padding-left: 2.5em; + } + + .split.style1 > :nth-child(2n - 1) { + width: calc(66.66666% - 2.5em); + } + + .split.style1 > :nth-child(2n) { + width: calc(33.33333% - 2.5em); + } + + @media screen and (max-width: 1680px) { + + .split > * { + width: calc(50% - 2em); + } + + .split > :nth-child(2n - 1) { + padding-right: 2em; + } + + .split > :nth-child(2n) { + padding-left: 2em; + } + + .split.style1 > :nth-child(2n - 1) { + width: calc(66.66666% - 2em); + } + + .split.style1 > :nth-child(2n) { + width: calc(33.33333% - 2em); + } + + } + + @media screen and (max-width: 980px) { + + .split { + display: block; + } + + .split > * { + border-top: solid 1px rgba(255, 255, 255, 0.15); + margin: 4em 0 0 0; + padding: 4em 0 0 0; + width: 100% !important; + } + + .split > :nth-child(2n - 1) { + border-right: 0; + padding-right: 0; + } + + .split > :nth-child(2n) { + padding-left: 0; + } + + .split > :first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; + } + + } + + @media screen and (max-width: 736px) { + + .split > * { + margin: 3em 0 0 0; + padding: 3em 0 0 0; + } + + } + +/* Spotlights */ + + .spotlights > section { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-direction: row; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + min-height: 22.5em; + } + + body.is-ie .spotlights > section { + min-height: 0; + } + + .spotlights > section > .image { + background-position: center center; + background-size: cover; + border-radius: 0; + display: block; + position: relative; + width: 25em; + } + + .spotlights > section > .image img { + border-radius: 0; + display: block; + } + + .spotlights > section > .image:before { + -moz-transition: opacity 1s ease; + -webkit-transition: opacity 1s ease; + -ms-transition: opacity 1s ease; + transition: opacity 1s ease; + background: rgba(49, 36, 80, 0.9); + content: ''; + display: block; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + } + + .spotlights > section > .content { + padding: 4em 5em 2em 5em ; + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -moz-justify-content: center; + -webkit-justify-content: center; + -ms-justify-content: center; + justify-content: center; + width: 50em; + -ms-flex: 1; + } + + .spotlights > section > .content > .inner { + -moz-transform: translateX(0) translateY(0); + -webkit-transform: translateX(0) translateY(0); + -ms-transform: translateX(0) translateY(0); + transform: translateX(0) translateY(0); + -moz-transition: opacity 1s ease, -moz-transform 1s ease; + -webkit-transition: opacity 1s ease, -webkit-transform 1s ease; + -ms-transition: opacity 1s ease, -ms-transform 1s ease; + transition: opacity 1s ease, transform 1s ease; + opacity: 1; + } + + .spotlights > section:nth-child(2) { + background-color: rgba(0, 0, 0, 0.05); + } + + .spotlights > section:nth-child(3) { + background-color: rgba(0, 0, 0, 0.1); + } + + .spotlights > section.inactive > .image:before, + body.is-preload .spotlights > section > .image:before { + opacity: 1; + } + + .spotlights > section.inactive > .content > .inner, + body.is-preload .spotlights > section > .content > .inner { + -moz-transform: translateX(-1em); + -webkit-transform: translateX(-1em); + -ms-transform: translateX(-1em); + transform: translateX(-1em); + opacity: 0; + } + + @media screen and (max-width: 1680px) { + + .spotlights > section > .content { + padding: 4em 4em 2em 4em ; + } + + } + + @media screen and (max-width: 980px) { + + .spotlights > section { + display: block; + } + + .spotlights > section > .image { + width: 100%; + height: 50vh; + } + + .spotlights > section > .content { + width: 100%; + } + + .spotlights > section.inactive > .content > .inner, + body.is-preload .spotlights > section > .content > .inner { + -moz-transform: translateY(1em); + -webkit-transform: translateY(1em); + -ms-transform: translateY(1em); + transform: translateY(1em); + } + + } + + @media screen and (max-width: 736px) { + + .spotlights > section > .image { + height: 50vh; + min-height: 15em; + } + + .spotlights > section > .content { + padding: 3em 2em 1em 2em ; + } + + } + +/* Table */ + + .table-wrapper { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + } + + table { + margin: 0 0 2em 0; + width: 100%; + } + + table tbody tr { + border: solid 1px rgba(255, 255, 255, 0.15); + border-left: 0; + border-right: 0; + } + + table tbody tr:nth-child(2n + 1) { + background-color: rgba(255, 255, 255, 0.05); + } + + table td { + padding: 0.75em 0.75em; + } + + table th { + color: #ffffff; + font-size: 1em; + font-weight: bold; + padding: 0 0.75em 0.75em 0.75em; + text-align: left; + } + + table thead { + border-bottom: solid 2px rgba(255, 255, 255, 0.15); + } + + table tfoot { + border-top: solid 2px rgba(255, 255, 255, 0.15); + } + + table.alt { + border-collapse: separate; + } + + table.alt tbody tr td { + border: solid 1px rgba(255, 255, 255, 0.15); + border-left-width: 0; + border-top-width: 0; + } + + table.alt tbody tr td:first-child { + border-left-width: 1px; + } + + table.alt tbody tr:first-child td { + border-top-width: 1px; + } + + table.alt thead { + border-bottom: 0; + } + + table.alt tfoot { + border-top: 0; + } + +/* Wrapper */ + + .wrapper { + position: relative; + } + + .wrapper > .inner { + padding: 5em 5em 3em 5em ; + max-width: 100%; + width: 75em; + } + + @media screen and (max-width: 1680px) { + + .wrapper > .inner { + padding: 4em 4em 2em 4em ; + } + + } + + @media screen and (max-width: 1280px) { + + .wrapper > .inner { + width: 100%; + } + + } + + @media screen and (max-width: 736px) { + + .wrapper > .inner { + padding: 3em 2em 1em 2em ; + } + + } + + .wrapper.alt { + background-color: #261c3e; + } + + .wrapper.style1 { + background-color: #5e42a6; + } + + .wrapper.style1-alt { + background-color: #493382; + } + + .wrapper.style2 { + background-color: #5052b5; + } + + .wrapper.style2-alt { + background-color: #3e4094; + } + + .wrapper.style3 { + background-color: #b74e91; + } + + .wrapper.style3-alt { + background-color: #953d75; + } + + .wrapper.fullscreen { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -moz-justify-content: center; + -webkit-justify-content: center; + -ms-justify-content: center; + justify-content: center; + min-height: 100vh; + } + + body.is-ie .wrapper.fullscreen { + height: 100vh; + } + + @media screen and (max-width: 1280px) { + + .wrapper.fullscreen { + min-height: calc(100vh - 2.5em); + } + + body.is-ie .wrapper.fullscreen { + height: calc(100vh - 2.5em); + } + + } + + @media screen and (max-width: 736px) { + + .wrapper.fullscreen { + padding: 2em 0; + min-height: 0; + } + + body.is-ie .wrapper.fullscreen { + height: auto; + } + + } + + .wrapper.fade-up > .inner { + -moz-transform: translateY(0); + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + -moz-transition: opacity 1s ease, -moz-transform 1s ease; + -webkit-transition: opacity 1s ease, -webkit-transform 1s ease; + -ms-transition: opacity 1s ease, -ms-transform 1s ease; + transition: opacity 1s ease, transform 1s ease; + opacity: 1.0; + } + + .wrapper.fade-up.inactive > .inner, + body.is-preload .wrapper.fade-up > .inner { + opacity: 0; + -moz-transform: translateY(1em); + -webkit-transform: translateY(1em); + -ms-transform: translateY(1em); + transform: translateY(1em); + } + + .wrapper.fade-down > .inner { + -moz-transform: translateY(0); + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + -moz-transition: opacity 1s ease, -moz-transform 1s ease; + -webkit-transition: opacity 1s ease, -webkit-transform 1s ease; + -ms-transition: opacity 1s ease, -ms-transform 1s ease; + transition: opacity 1s ease, transform 1s ease; + opacity: 1.0; + } + + .wrapper.fade-down.inactive > .inner, + body.is-preload .wrapper.fade-down > .inner { + opacity: 0; + -moz-transform: translateY(-1em); + -webkit-transform: translateY(-1em); + -ms-transform: translateY(-1em); + transform: translateY(-1em); + } + + .wrapper.fade > .inner { + -moz-transition: opacity 1s ease; + -webkit-transition: opacity 1s ease; + -ms-transition: opacity 1s ease; + transition: opacity 1s ease; + opacity: 1.0; + } + + .wrapper.fade.inactive > .inner, + body.is-preload .wrapper.fade > .inner { + opacity: 0; + } + +/* Header */ + + #header { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + background-color: #5e42a6; + cursor: default; + padding: 1.75em 2em; + } + + #header > .title { + border: 0; + color: #ffffff; + display: block; + font-size: 1.25em; + font-weight: bold; + } + + #header > nav { + -moz-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: right; + } + + #header > nav > ul { + margin: 0; + padding: 0; + } + + #header > nav > ul > li { + display: inline-block; + margin-left: 1.75em; + padding: 0; + vertical-align: middle; + } + + #header > nav > ul > li:first-child { + margin-left: 0; + } + + #header > nav > ul > li a { + border: 0; + color: rgba(255, 255, 255, 0.35); + display: inline-block; + font-size: 0.6em; + font-weight: bold; + letter-spacing: 0.25em; + text-transform: uppercase; + } + + #header > nav > ul > li a:hover { + color: rgba(255, 255, 255, 0.55); + } + + #header > nav > ul > li a.active { + color: #ffffff; + } + + @media screen and (max-width: 736px) { + + #header { + padding: 1em 2em; + } + + } + + @media screen and (max-width: 480px) { + + #header { + display: block; + padding: 0 2em; + text-align: left; + } + + #header .title { + font-size: 1.25em; + padding: 1em 0; + } + + #header > nav { + border-top: solid 1px rgba(255, 255, 255, 0.15); + text-align: inherit; + } + + #header > nav > ul > li { + margin-left: 1.5em; + } + + #header > nav > ul > li a { + height: 6em; + line-height: 6em; + } + + } + +/* Wrapper (main) */ + + #sidebar + #wrapper { + margin-left: 18em; + } + + @media screen and (max-width: 1280px) { + + #sidebar + #wrapper { + margin-left: 0; + padding-top: 3.5em; + } + + } + + @media screen and (max-width: 736px) { + + #sidebar + #wrapper { + padding-top: 0; + } + + } + + #header + #wrapper > .wrapper > .inner { + margin: 0 auto; + } + +/* Footer */ + + #sidebar + #wrapper + #footer { + margin-left: 18em; + } + + @media screen and (max-width: 1280px) { + + #sidebar + #wrapper + #footer { + margin-left: 0; + } + + } + + #footer > .inner a { + border-bottom-color: rgba(255, 255, 255, 0.15); + } + + #footer > .inner a:hover { + border-bottom-color: transparent; + } + + #footer > .inner .menu { + font-size: 0.8em; + color: rgba(255, 255, 255, 0.15); + } + + #header + #wrapper + #footer > .inner { + margin: 0 auto; + } + +/* Sidebar */ + + #sidebar { + padding: 2.5em 2.5em 0.5em 2.5em ; + background: #312450; + cursor: default; + height: 100vh; + left: 0; + overflow-x: hidden; + overflow-y: auto; + position: fixed; + text-align: right; + top: 0; + width: 18em; + z-index: 10000; + } + + #sidebar > .inner { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + -moz-flex-direction: column; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -moz-justify-content: center; + -webkit-justify-content: center; + -ms-justify-content: center; + justify-content: center; + -moz-transform: translateY(0); + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + -moz-transition: opacity 1s ease; + -webkit-transition: opacity 1s ease; + -ms-transition: opacity 1s ease; + transition: opacity 1s ease; + min-height: 100%; + opacity: 1; + width: 100%; + } + + body.is-ie #sidebar > .inner { + height: 100%; + } + + #sidebar nav > ul { + list-style: none; + padding: 0; + } + + #sidebar nav > ul > li { + -moz-transform: translateY(0); + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + -moz-transition: opacity 0.15s ease, -moz-transform 0.75s ease; + -webkit-transition: opacity 0.15s ease, -webkit-transform 0.75s ease; + -ms-transition: opacity 0.15s ease, -ms-transform 0.75s ease; + transition: opacity 0.15s ease, transform 0.75s ease; + margin: 1.5em 0 0 0; + opacity: 1; + padding: 0; + position: relative; + } + + #sidebar nav > ul > li:first-child { + margin: 0; + } + + #sidebar nav > ul > li:nth-child(1) { + -moz-transition-delay: 0.45s; + -webkit-transition-delay: 0.45s; + -ms-transition-delay: 0.45s; + transition-delay: 0.45s; + } + + #sidebar nav > ul > li:nth-child(2) { + -moz-transition-delay: 0.65s; + -webkit-transition-delay: 0.65s; + -ms-transition-delay: 0.65s; + transition-delay: 0.65s; + } + + #sidebar nav > ul > li:nth-child(3) { + -moz-transition-delay: 0.85s; + -webkit-transition-delay: 0.85s; + -ms-transition-delay: 0.85s; + transition-delay: 0.85s; + } + + #sidebar nav > ul > li:nth-child(4) { + -moz-transition-delay: 1.05s; + -webkit-transition-delay: 1.05s; + -ms-transition-delay: 1.05s; + transition-delay: 1.05s; + } + + #sidebar nav > ul > li:nth-child(5) { + -moz-transition-delay: 1.25s; + -webkit-transition-delay: 1.25s; + -ms-transition-delay: 1.25s; + transition-delay: 1.25s; + } + + #sidebar nav > ul > li:nth-child(6) { + -moz-transition-delay: 1.45s; + -webkit-transition-delay: 1.45s; + -ms-transition-delay: 1.45s; + transition-delay: 1.45s; + } + + #sidebar nav > ul > li:nth-child(7) { + -moz-transition-delay: 1.65s; + -webkit-transition-delay: 1.65s; + -ms-transition-delay: 1.65s; + transition-delay: 1.65s; + } + + #sidebar nav > ul > li:nth-child(8) { + -moz-transition-delay: 1.85s; + -webkit-transition-delay: 1.85s; + -ms-transition-delay: 1.85s; + transition-delay: 1.85s; + } + + #sidebar nav > ul > li:nth-child(9) { + -moz-transition-delay: 2.05s; + -webkit-transition-delay: 2.05s; + -ms-transition-delay: 2.05s; + transition-delay: 2.05s; + } + + #sidebar nav > ul > li:nth-child(10) { + -moz-transition-delay: 2.25s; + -webkit-transition-delay: 2.25s; + -ms-transition-delay: 2.25s; + transition-delay: 2.25s; + } + + #sidebar nav > ul > li:nth-child(11) { + -moz-transition-delay: 2.45s; + -webkit-transition-delay: 2.45s; + -ms-transition-delay: 2.45s; + transition-delay: 2.45s; + } + + #sidebar nav > ul > li:nth-child(12) { + -moz-transition-delay: 2.65s; + -webkit-transition-delay: 2.65s; + -ms-transition-delay: 2.65s; + transition-delay: 2.65s; + } + + #sidebar nav > ul > li:nth-child(13) { + -moz-transition-delay: 2.85s; + -webkit-transition-delay: 2.85s; + -ms-transition-delay: 2.85s; + transition-delay: 2.85s; + } + + #sidebar nav > ul > li:nth-child(14) { + -moz-transition-delay: 3.05s; + -webkit-transition-delay: 3.05s; + -ms-transition-delay: 3.05s; + transition-delay: 3.05s; + } + + #sidebar nav > ul > li:nth-child(15) { + -moz-transition-delay: 3.25s; + -webkit-transition-delay: 3.25s; + -ms-transition-delay: 3.25s; + transition-delay: 3.25s; + } + + #sidebar nav > ul > li:nth-child(16) { + -moz-transition-delay: 3.45s; + -webkit-transition-delay: 3.45s; + -ms-transition-delay: 3.45s; + transition-delay: 3.45s; + } + + #sidebar nav > ul > li:nth-child(17) { + -moz-transition-delay: 3.65s; + -webkit-transition-delay: 3.65s; + -ms-transition-delay: 3.65s; + transition-delay: 3.65s; + } + + #sidebar nav > ul > li:nth-child(18) { + -moz-transition-delay: 3.85s; + -webkit-transition-delay: 3.85s; + -ms-transition-delay: 3.85s; + transition-delay: 3.85s; + } + + #sidebar nav > ul > li:nth-child(19) { + -moz-transition-delay: 4.05s; + -webkit-transition-delay: 4.05s; + -ms-transition-delay: 4.05s; + transition-delay: 4.05s; + } + + #sidebar nav > ul > li:nth-child(20) { + -moz-transition-delay: 4.25s; + -webkit-transition-delay: 4.25s; + -ms-transition-delay: 4.25s; + transition-delay: 4.25s; + } + + #sidebar nav a { + -moz-transition: color 0.2s ease; + -webkit-transition: color 0.2s ease; + -ms-transition: color 0.2s ease; + transition: color 0.2s ease; + border: 0; + color: rgba(255, 255, 255, 0.35); + display: block; + font-size: 0.6em; + font-weight: bold; + letter-spacing: 0.25em; + line-height: 1.75; + outline: 0; + padding: 1.35em 0; + position: relative; + text-decoration: none; + text-transform: uppercase; + } + + #sidebar nav a:before, #sidebar nav a:after { + border-radius: 0.2em; + bottom: 0; + content: ''; + height: 0.2em; + position: absolute; + right: 0; + width: 100%; + } + + #sidebar nav a:before { + background: #3c2c62; + } + + #sidebar nav a:after { + background-image: -moz-linear-gradient(to right, #5e42a6, #b74e91); + background-image: -webkit-linear-gradient(to right, #5e42a6, #b74e91); + background-image: -ms-linear-gradient(to right, #5e42a6, #b74e91); + background-image: linear-gradient(to right, #5e42a6, #b74e91); + -moz-transition: max-width 0.2s ease; + -webkit-transition: max-width 0.2s ease; + -ms-transition: max-width 0.2s ease; + transition: max-width 0.2s ease; + max-width: 0; + } + + #sidebar nav a:hover { + color: rgba(255, 255, 255, 0.55); + } + + #sidebar nav a.active { + color: #ffffff; + } + + #sidebar nav a.active:after { + max-width: 100%; + } + + body.is-preload #sidebar > .inner { + opacity: 0; + } + + body.is-preload #sidebar nav ul li { + -moz-transform: translateY(2em); + -webkit-transform: translateY(2em); + -ms-transform: translateY(2em); + transform: translateY(2em); + opacity: 0; + } + + @media screen and (max-width: 1280px) { + + #sidebar { + height: 3.5em; + left: 0; + line-height: 3.5em; + overflow: hidden; + padding: 0; + text-align: center; + top: 0; + width: 100%; + } + + #sidebar > .inner { + -moz-flex-direction: row; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -moz-align-items: -moz-stretch; + -webkit-align-items: -webkit-stretch; + -ms-align-items: -ms-stretch; + align-items: stretch; + height: inherit; + line-height: inherit; + } + + #sidebar nav { + height: inherit; + line-height: inherit; + } + + #sidebar nav ul { + display: -moz-flex; + display: -webkit-flex; + display: -ms-flex; + display: flex; + height: inherit; + line-height: inherit; + margin: 0; + } + + #sidebar nav ul li { + display: block; + height: inherit; + line-height: inherit; + margin: 0 0 0 2em; + padding: 0; + } + + #sidebar nav a { + height: inherit; + line-height: inherit; + padding: 0; + } + + #sidebar nav a:after { + background-image: none; + background-color: #b74e91; + } + + } + + @media screen and (max-width: 736px) { + + #sidebar { + display: none; + } + + } + +/* Intro */ + + #intro { + background-attachment: fixed; + background-image: url("images/intro.svg"); + background-position: top right; + background-repeat: no-repeat; + background-size: 100% 100%; + } + + #intro p { + font-size: 1.25em; + } + + @media screen and (max-width: 980px) { + + #intro p br { + display: none; + } + + } + + @media screen and (max-width: 736px) { + + #intro p { + font-size: 1em; + } + + } + + @media screen and (max-width: 1280px) { + + #intro { + background-attachment: scroll; + } + + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/css/noscript.css b/pythoncms/static/themes/front/hyperspace/assets/css/noscript.css new file mode 100644 index 0000000..53a17fa --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/css/noscript.css @@ -0,0 +1,43 @@ +/* + Hyperspace by HTML5 UP + html5up.net | @ajlkn + Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +*/ + +/* Spotlights */ + + .spotlights > section > .image:before { + opacity: 0 !important; + } + + .spotlights > section > .content > .inner { + -moz-transform: none !important; + -webkit-transform: none !important; + -ms-transform: none !important; + transform: none !important; + opacity: 1 !important; + } + +/* Wrapper */ + + .wrapper > .inner { + opacity: 1 !important; + -moz-transform: none !important; + -webkit-transform: none !important; + -ms-transform: none !important; + transform: none !important; + } + +/* Sidebar */ + + #sidebar > .inner { + opacity: 1 !important; + } + + #sidebar nav > ul > li { + -moz-transform: none !important; + -webkit-transform: none !important; + -ms-transform: none !important; + transform: none !important; + opacity: 1 !important; + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/js/breakpoints.min.js b/pythoncms/static/themes/front/hyperspace/assets/js/breakpoints.min.js new file mode 100644 index 0000000..32419cc --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/js/breakpoints.min.js @@ -0,0 +1,2 @@ +/* breakpoints.js v1.0 | @ajlkn | MIT licensed */ +var breakpoints=function(){"use strict";function e(e){t.init(e)}var t={list:null,media:{},events:[],init:function(e){t.list=e,window.addEventListener("resize",t.poll),window.addEventListener("orientationchange",t.poll),window.addEventListener("load",t.poll),window.addEventListener("fullscreenchange",t.poll)},active:function(e){var n,a,s,i,r,d,c;if(!(e in t.media)){if(">="==e.substr(0,2)?(a="gte",n=e.substr(2)):"<="==e.substr(0,2)?(a="lte",n=e.substr(2)):">"==e.substr(0,1)?(a="gt",n=e.substr(1)):"<"==e.substr(0,1)?(a="lt",n=e.substr(1)):"!"==e.substr(0,1)?(a="not",n=e.substr(1)):(a="eq",n=e),n&&n in t.list)if(i=t.list[n],Array.isArray(i)){if(r=parseInt(i[0]),d=parseInt(i[1]),isNaN(r)){if(isNaN(d))return;c=i[1].substr(String(d).length)}else c=i[0].substr(String(r).length);if(isNaN(r))switch(a){case"gte":s="screen";break;case"lte":s="screen and (max-width: "+d+c+")";break;case"gt":s="screen and (min-width: "+(d+1)+c+")";break;case"lt":s="screen and (max-width: -1px)";break;case"not":s="screen and (min-width: "+(d+1)+c+")";break;default:s="screen and (max-width: "+d+c+")"}else if(isNaN(d))switch(a){case"gte":s="screen and (min-width: "+r+c+")";break;case"lte":s="screen";break;case"gt":s="screen and (max-width: -1px)";break;case"lt":s="screen and (max-width: "+(r-1)+c+")";break;case"not":s="screen and (max-width: "+(r-1)+c+")";break;default:s="screen and (min-width: "+r+c+")"}else switch(a){case"gte":s="screen and (min-width: "+r+c+")";break;case"lte":s="screen and (max-width: "+d+c+")";break;case"gt":s="screen and (min-width: "+(d+1)+c+")";break;case"lt":s="screen and (max-width: "+(r-1)+c+")";break;case"not":s="screen and (max-width: "+(r-1)+c+"), screen and (min-width: "+(d+1)+c+")";break;default:s="screen and (min-width: "+r+c+") and (max-width: "+d+c+")"}}else s="("==i.charAt(0)?"screen and "+i:i;t.media[e]=!!s&&s}return t.media[e]!==!1&&window.matchMedia(t.media[e]).matches},on:function(e,n){t.events.push({query:e,handler:n,state:!1}),t.active(e)&&n()},poll:function(){var e,n;for(e=0;e+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 01){for(var r=0;r=i&&o>=t};break;case"bottom":h=function(t,e,n,i,o){return n>=i&&o>=n};break;case"middle":h=function(t,e,n,i,o){return e>=i&&o>=e};break;case"top-only":h=function(t,e,n,i,o){return i>=t&&n>=i};break;case"bottom-only":h=function(t,e,n,i,o){return n>=o&&o>=t};break;default:case"default":h=function(t,e,n,i,o){return n>=i&&o>=t}}return c=function(t){var i,o,l,s,r,a,u=this.state,h=!1,c=this.$element.offset();i=n.height(),o=t+i/2,l=t+i,s=this.$element.outerHeight(),r=c.top+e(this.options.top,s,i),a=c.top+s-e(this.options.bottom,s,i),h=this.test(t,o,l,r,a),h!=u&&(this.state=h,h?this.options.enter&&this.options.enter.apply(this.element):this.options.leave&&this.options.leave.apply(this.element)),this.options.scroll&&this.options.scroll.apply(this.element,[(o-r)/(a-r)])},p={id:a,options:u,test:h,handler:c,state:null,element:this,$element:s,timeoutId:null},o[a]=p,s.data("_scrollexId",p.id),p.options.initialize&&p.options.initialize.apply(this),s},jQuery.fn.unscrollex=function(){var e=t(this);if(0==this.length)return e;if(this.length>1){for(var n=0;n1){for(o=0;o 0) { + + var $sidebar_a = $sidebar.find('a'); + + $sidebar_a + .addClass('scrolly') + .on('click', function() { + + var $this = $(this); + + // External link? Bail. + if ($this.attr('href').charAt(0) != '#') + return; + + // Deactivate all links. + $sidebar_a.removeClass('active'); + + // Activate link *and* lock it (so Scrollex doesn't try to activate other links as we're scrolling to this one's section). + $this + .addClass('active') + .addClass('active-locked'); + + }) + .each(function() { + + var $this = $(this), + id = $this.attr('href'), + $section = $(id); + + // No section for this link? Bail. + if ($section.length < 1) + return; + + // Scrollex. + $section.scrollex({ + mode: 'middle', + top: '-20vh', + bottom: '-20vh', + initialize: function() { + + // Deactivate section. + $section.addClass('inactive'); + + }, + enter: function() { + + // Activate section. + $section.removeClass('inactive'); + + // No locked links? Deactivate all links and activate this section's one. + if ($sidebar_a.filter('.active-locked').length == 0) { + + $sidebar_a.removeClass('active'); + $this.addClass('active'); + + } + + // Otherwise, if this section's link is the one that's locked, unlock it. + else if ($this.hasClass('active-locked')) + $this.removeClass('active-locked'); + + } + }); + + }); + + } + + // Scrolly. + $('.scrolly').scrolly({ + speed: 1000, + offset: function() { + + // If <=large, >small, and sidebar is present, use its height as the offset. + if (breakpoints.active('<=large') + && !breakpoints.active('<=small') + && $sidebar.length > 0) + return $sidebar.height(); + + return 0; + + } + }); + + // Spotlights. + $('.spotlights > section') + .scrollex({ + mode: 'middle', + top: '-10vh', + bottom: '-10vh', + initialize: function() { + + // Deactivate section. + $(this).addClass('inactive'); + + }, + enter: function() { + + // Activate section. + $(this).removeClass('inactive'); + + } + }) + .each(function() { + + var $this = $(this), + $image = $this.find('.image'), + $img = $image.find('img'), + x; + + // Assign image. + $image.css('background-image', 'url(' + $img.attr('src') + ')'); + + // Set background position. + if (x = $img.data('position')) + $image.css('background-position', x); + + // Hide . + $img.hide(); + + }); + + // Features. + $('.features') + .scrollex({ + mode: 'middle', + top: '-20vh', + bottom: '-20vh', + initialize: function() { + + // Deactivate section. + $(this).addClass('inactive'); + + }, + enter: function() { + + // Activate section. + $(this).removeClass('inactive'); + + } + }); + +})(jQuery); diff --git a/pythoncms/static/themes/front/hyperspace/assets/js/util.js b/pythoncms/static/themes/front/hyperspace/assets/js/util.js new file mode 100644 index 0000000..3633ca6 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/js/util.js @@ -0,0 +1,587 @@ +(function($) { + + /** + * Generate an indented list of links from a nav. Meant for use with panel(). + * @return {jQuery} jQuery object. + */ + $.fn.navList = function() { + + var $this = $(this); + $a = $this.find('a'), + b = []; + + $a.each(function() { + + var $this = $(this), + indent = Math.max(0, $this.parents('li').length - 1), + href = $this.attr('href'), + target = $this.attr('target'); + + b.push( + '' + + '' + + $this.text() + + '' + ); + + }); + + return b.join(''); + + }; + + /** + * Panel-ify an element. + * @param {object} userConfig User config. + * @return {jQuery} jQuery object. + */ + $.fn.panel = function(userConfig) { + + // No elements? + if (this.length == 0) + return $this; + + // Multiple elements? + if (this.length > 1) { + + for (var i=0; i < this.length; i++) + $(this[i]).panel(userConfig); + + return $this; + + } + + // Vars. + var $this = $(this), + $body = $('body'), + $window = $(window), + id = $this.attr('id'), + config; + + // Config. + config = $.extend({ + + // Delay. + delay: 0, + + // Hide panel on link click. + hideOnClick: false, + + // Hide panel on escape keypress. + hideOnEscape: false, + + // Hide panel on swipe. + hideOnSwipe: false, + + // Reset scroll position on hide. + resetScroll: false, + + // Reset forms on hide. + resetForms: false, + + // Side of viewport the panel will appear. + side: null, + + // Target element for "class". + target: $this, + + // Class to toggle. + visibleClass: 'visible' + + }, userConfig); + + // Expand "target" if it's not a jQuery object already. + if (typeof config.target != 'jQuery') + config.target = $(config.target); + + // Panel. + + // Methods. + $this._hide = function(event) { + + // Already hidden? Bail. + if (!config.target.hasClass(config.visibleClass)) + return; + + // If an event was provided, cancel it. + if (event) { + + event.preventDefault(); + event.stopPropagation(); + + } + + // Hide. + config.target.removeClass(config.visibleClass); + + // Post-hide stuff. + window.setTimeout(function() { + + // Reset scroll position. + if (config.resetScroll) + $this.scrollTop(0); + + // Reset forms. + if (config.resetForms) + $this.find('form').each(function() { + this.reset(); + }); + + }, config.delay); + + }; + + // Vendor fixes. + $this + .css('-ms-overflow-style', '-ms-autohiding-scrollbar') + .css('-webkit-overflow-scrolling', 'touch'); + + // Hide on click. + if (config.hideOnClick) { + + $this.find('a') + .css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)'); + + $this + .on('click', 'a', function(event) { + + var $a = $(this), + href = $a.attr('href'), + target = $a.attr('target'); + + if (!href || href == '#' || href == '' || href == '#' + id) + return; + + // Cancel original event. + event.preventDefault(); + event.stopPropagation(); + + // Hide panel. + $this._hide(); + + // Redirect to href. + window.setTimeout(function() { + + if (target == '_blank') + window.open(href); + else + window.location.href = href; + + }, config.delay + 10); + + }); + + } + + // Event: Touch stuff. + $this.on('touchstart', function(event) { + + $this.touchPosX = event.originalEvent.touches[0].pageX; + $this.touchPosY = event.originalEvent.touches[0].pageY; + + }) + + $this.on('touchmove', function(event) { + + if ($this.touchPosX === null + || $this.touchPosY === null) + return; + + var diffX = $this.touchPosX - event.originalEvent.touches[0].pageX, + diffY = $this.touchPosY - event.originalEvent.touches[0].pageY, + th = $this.outerHeight(), + ts = ($this.get(0).scrollHeight - $this.scrollTop()); + + // Hide on swipe? + if (config.hideOnSwipe) { + + var result = false, + boundary = 20, + delta = 50; + + switch (config.side) { + + case 'left': + result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta); + break; + + case 'right': + result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta)); + break; + + case 'top': + result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta); + break; + + case 'bottom': + result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta)); + break; + + default: + break; + + } + + if (result) { + + $this.touchPosX = null; + $this.touchPosY = null; + $this._hide(); + + return false; + + } + + } + + // Prevent vertical scrolling past the top or bottom. + if (($this.scrollTop() < 0 && diffY < 0) + || (ts > (th - 2) && ts < (th + 2) && diffY > 0)) { + + event.preventDefault(); + event.stopPropagation(); + + } + + }); + + // Event: Prevent certain events inside the panel from bubbling. + $this.on('click touchend touchstart touchmove', function(event) { + event.stopPropagation(); + }); + + // Event: Hide panel if a child anchor tag pointing to its ID is clicked. + $this.on('click', 'a[href="#' + id + '"]', function(event) { + + event.preventDefault(); + event.stopPropagation(); + + config.target.removeClass(config.visibleClass); + + }); + + // Body. + + // Event: Hide panel on body click/tap. + $body.on('click touchend', function(event) { + $this._hide(event); + }); + + // Event: Toggle. + $body.on('click', 'a[href="#' + id + '"]', function(event) { + + event.preventDefault(); + event.stopPropagation(); + + config.target.toggleClass(config.visibleClass); + + }); + + // Window. + + // Event: Hide on ESC. + if (config.hideOnEscape) + $window.on('keydown', function(event) { + + if (event.keyCode == 27) + $this._hide(event); + + }); + + return $this; + + }; + + /** + * Apply "placeholder" attribute polyfill to one or more forms. + * @return {jQuery} jQuery object. + */ + $.fn.placeholder = function() { + + // Browser natively supports placeholders? Bail. + if (typeof (document.createElement('input')).placeholder != 'undefined') + return $(this); + + // No elements? + if (this.length == 0) + return $this; + + // Multiple elements? + if (this.length > 1) { + + for (var i=0; i < this.length; i++) + $(this[i]).placeholder(); + + return $this; + + } + + // Vars. + var $this = $(this); + + // Text, TextArea. + $this.find('input[type=text],textarea') + .each(function() { + + var i = $(this); + + if (i.val() == '' + || i.val() == i.attr('placeholder')) + i + .addClass('polyfill-placeholder') + .val(i.attr('placeholder')); + + }) + .on('blur', function() { + + var i = $(this); + + if (i.attr('name').match(/-polyfill-field$/)) + return; + + if (i.val() == '') + i + .addClass('polyfill-placeholder') + .val(i.attr('placeholder')); + + }) + .on('focus', function() { + + var i = $(this); + + if (i.attr('name').match(/-polyfill-field$/)) + return; + + if (i.val() == i.attr('placeholder')) + i + .removeClass('polyfill-placeholder') + .val(''); + + }); + + // Password. + $this.find('input[type=password]') + .each(function() { + + var i = $(this); + var x = $( + $('
') + .append(i.clone()) + .remove() + .html() + .replace(/type="password"/i, 'type="text"') + .replace(/type=password/i, 'type=text') + ); + + if (i.attr('id') != '') + x.attr('id', i.attr('id') + '-polyfill-field'); + + if (i.attr('name') != '') + x.attr('name', i.attr('name') + '-polyfill-field'); + + x.addClass('polyfill-placeholder') + .val(x.attr('placeholder')).insertAfter(i); + + if (i.val() == '') + i.hide(); + else + x.hide(); + + i + .on('blur', function(event) { + + event.preventDefault(); + + var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]'); + + if (i.val() == '') { + + i.hide(); + x.show(); + + } + + }); + + x + .on('focus', function(event) { + + event.preventDefault(); + + var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']'); + + x.hide(); + + i + .show() + .focus(); + + }) + .on('keypress', function(event) { + + event.preventDefault(); + x.val(''); + + }); + + }); + + // Events. + $this + .on('submit', function() { + + $this.find('input[type=text],input[type=password],textarea') + .each(function(event) { + + var i = $(this); + + if (i.attr('name').match(/-polyfill-field$/)) + i.attr('name', ''); + + if (i.val() == i.attr('placeholder')) { + + i.removeClass('polyfill-placeholder'); + i.val(''); + + } + + }); + + }) + .on('reset', function(event) { + + event.preventDefault(); + + $this.find('select') + .val($('option:first').val()); + + $this.find('input,textarea') + .each(function() { + + var i = $(this), + x; + + i.removeClass('polyfill-placeholder'); + + switch (this.type) { + + case 'submit': + case 'reset': + break; + + case 'password': + i.val(i.attr('defaultValue')); + + x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]'); + + if (i.val() == '') { + i.hide(); + x.show(); + } + else { + i.show(); + x.hide(); + } + + break; + + case 'checkbox': + case 'radio': + i.attr('checked', i.attr('defaultValue')); + break; + + case 'text': + case 'textarea': + i.val(i.attr('defaultValue')); + + if (i.val() == '') { + i.addClass('polyfill-placeholder'); + i.val(i.attr('placeholder')); + } + + break; + + default: + i.val(i.attr('defaultValue')); + break; + + } + }); + + }); + + return $this; + + }; + + /** + * Moves elements to/from the first positions of their respective parents. + * @param {jQuery} $elements Elements (or selector) to move. + * @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations. + */ + $.prioritize = function($elements, condition) { + + var key = '__prioritize'; + + // Expand $elements if it's not already a jQuery object. + if (typeof $elements != 'jQuery') + $elements = $($elements); + + // Step through elements. + $elements.each(function() { + + var $e = $(this), $p, + $parent = $e.parent(); + + // No parent? Bail. + if ($parent.length == 0) + return; + + // Not moved? Move it. + if (!$e.data(key)) { + + // Condition is false? Bail. + if (!condition) + return; + + // Get placeholder (which will serve as our point of reference for when this element needs to move back). + $p = $e.prev(); + + // Couldn't find anything? Means this element's already at the top, so bail. + if ($p.length == 0) + return; + + // Move element to top of parent. + $e.prependTo($parent); + + // Mark element as moved. + $e.data(key, $p); + + } + + // Moved already? + else { + + // Condition is true? Bail. + if (condition) + return; + + $p = $e.data(key); + + // Move element back to its original location (using our placeholder). + $e.insertAfter($p); + + // Unmark element as moved. + $e.removeData(key); + + } + + }); + + }; + +})(jQuery); diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/base/_page.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/base/_page.scss new file mode 100644 index 0000000..fecf038 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/base/_page.scss @@ -0,0 +1,47 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Basic */ + + // MSIE: Required for IEMobile. + @-ms-viewport { + width: device-width; + } + + // MSIE: Prevents scrollbar from overlapping content. + body { + -ms-overflow-style: scrollbar; + } + + // Ensures page width is always >=320px. + @include breakpoint('<=xsmall') { + html, body { + min-width: 320px; + } + } + + // Set box model to border-box. + // Based on css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice + html { + box-sizing: border-box; + } + + *, *:before, *:after { + box-sizing: inherit; + } + + body { + background: _palette(bg); + + // Stops initial animations until page loads. + &.is-preload { + *, *:before, *:after { + @include vendor('animation', 'none !important'); + @include vendor('transition', 'none !important'); + } + } + + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/base/_reset.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/base/_reset.scss new file mode 100644 index 0000000..ea2a932 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/base/_reset.scss @@ -0,0 +1,76 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +// Reset. +// Based on meyerweb.com/eric/tools/css/reset (v2.0 | 20110126 | License: public domain) + + html, body, div, span, applet, object, + iframe, h1, h2, h3, h4, h5, h6, p, blockquote, + pre, a, abbr, acronym, address, big, cite, + code, del, dfn, em, img, ins, kbd, q, s, samp, + small, strike, strong, sub, sup, tt, var, b, + u, i, center, dl, dt, dd, ol, ul, li, fieldset, + form, label, legend, table, caption, tbody, + tfoot, thead, tr, th, td, article, aside, + canvas, details, embed, figure, figcaption, + footer, header, hgroup, menu, nav, output, ruby, + section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; + } + + article, aside, details, figcaption, figure, + footer, header, hgroup, menu, nav, section { + display: block; + } + + body { + line-height: 1; + } + + ol, ul { + list-style:none; + } + + blockquote, q { + quotes: none; + + &:before, + &:after { + content: ''; + content: none; + } + } + + table { + border-collapse: collapse; + border-spacing: 0; + } + + body { + -webkit-text-size-adjust: none; + } + + mark { + background-color: transparent; + color: inherit; + } + + input::-moz-focus-inner { + border: 0; + padding: 0; + } + + input, select, textarea { + -moz-appearance: none; + -webkit-appearance: none; + -ms-appearance: none; + appearance: none; + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/base/_typography.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/base/_typography.scss new file mode 100644 index 0000000..664f9a6 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/base/_typography.scss @@ -0,0 +1,200 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Type */ + + body, input, select, textarea { + color: _palette(fg); + font-family: _font(family); + font-size: 16.5pt; + font-weight: _font(weight); + line-height: 1.75; + + @include breakpoint('<=xlarge') { + font-size: 13pt; + } + + @include breakpoint('<=large') { + font-size: 12pt; + } + + @include breakpoint('<=xxsmall') { + font-size: 11pt; + } + } + + a { + @include vendor('transition', ( + 'color #{_duration(transition)} ease', + 'border-bottom-color #{_duration(transition)} ease' + )); + border-bottom: dotted 1px _palette(fg-light); + color: inherit; + text-decoration: none; + + &:hover { + border-bottom-color: transparent; + color: _palette(fg-bold); + } + } + + strong, b { + color: _palette(fg-bold); + font-weight: _font(weight-bold); + } + + em, i { + font-style: italic; + } + + p { + margin: 0 0 _size(element-margin) 0; + } + + h1, h2, h3, h4, h5, h6 { + color: _palette(fg-bold); + font-weight: _font(weight-bold); + line-height: 1.5; + margin: 0 0 (_size(element-margin) * 0.25) 0; + + a { + color: inherit; + text-decoration: none; + } + } + + h1 { + font-size: 2.75em; + + &.major { + margin: 0 0 (_size(element-margin) * 0.65) 0; + position: relative; + padding-bottom: 0.35em; + + &:after { + @include vendor('background-image', 'linear-gradient(to right, #{_palette(accent1)}, #{_palette(accent3)})'); + @include vendor('transition', 'max-width #{_duration(transition)} ease'); + border-radius: 0.2em; + bottom: 0; + content: ''; + height: 0.05em; + position: absolute; + right: 0; + width: 100%; + } + } + } + + h2 { + font-size: 1.75em; + } + + h3 { + font-size: 1.1em; + } + + h4 { + font-size: 1em; + } + + h5 { + font-size: 0.8em; + } + + h6 { + font-size: 0.6em; + } + + @include breakpoint('<=small') { + h1 { + font-size: 2em; + } + + h2 { + font-size: 1.25em; + } + + h3 { + font-size: 1em; + } + + h4 { + font-size: 0.8em; + } + + h5 { + font-size: 0.6em; + } + + h6 { + font-size: 0.6em; + } + } + + sub { + font-size: 0.8em; + position: relative; + top: 0.5em; + } + + sup { + font-size: 0.8em; + position: relative; + top: -0.5em; + } + + blockquote { + border-left: solid (_size(border-width) * 4) _palette(border); + font-style: italic; + margin: 0 0 _size(element-margin) 0; + padding: (_size(element-margin) / 4) 0 (_size(element-margin) / 4) _size(element-margin); + } + + code { + background: _palette(border-bg); + border-radius: _size(border-radius); + border: solid _size(border-width) _palette(border); + font-family: _font(family-fixed); + font-size: 0.9em; + margin: 0 0.25em; + padding: 0.25em 0.65em; + } + + pre { + -webkit-overflow-scrolling: touch; + font-family: _font(family-fixed); + font-size: 0.9em; + margin: 0 0 _size(element-margin) 0; + + code { + display: block; + line-height: 1.75em; + padding: 1em 1.5em; + overflow-x: auto; + } + } + + hr { + border: 0; + border-bottom: solid _size(border-width) _palette(border); + margin: _size(element-margin) 0; + + &.major { + margin: (_size(element-margin) * 1.5) 0; + } + } + + .align-left { + text-align: left; + } + + .align-center { + text-align: center; + } + + .align-right { + text-align: right; + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_actions.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_actions.scss new file mode 100644 index 0000000..ed7fda3 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_actions.scss @@ -0,0 +1,101 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Actions */ + + ul.actions { + @include vendor('display', 'flex'); + cursor: default; + list-style: none; + margin-left: (_size(element-margin) * -0.5); + padding-left: 0; + + li { + padding: 0 0 0 (_size(element-margin) * 0.5); + vertical-align: middle; + } + + &.special { + @include vendor('justify-content', 'center'); + width: 100%; + margin-left: 0; + + li { + &:first-child { + padding-left: 0; + } + } + } + + &.stacked { + @include vendor('flex-direction', 'column'); + margin-left: 0; + + li { + padding: (_size(element-margin) * 0.65) 0 0 0; + + &:first-child { + padding-top: 0; + } + } + } + + &.fit { + width: calc(100% + #{_size(element-margin) * 0.5}); + + li { + @include vendor('flex-grow', '1'); + @include vendor('flex-shrink', '1'); + width: 100%; + + > * { + width: 100%; + } + } + + &.stacked { + width: 100%; + } + } + + @include breakpoint('<=xsmall') { + &:not(.fixed) { + @include vendor('flex-direction', 'column'); + margin-left: 0; + width: 100% !important; + + li { + @include vendor('flex-grow', '1'); + @include vendor('flex-shrink', '1'); + padding: (_size(element-margin) * 0.5) 0 0 0; + text-align: center; + width: 100%; + + > * { + width: 100%; + } + + &:first-child { + padding-top: 0; + } + + input[type="submit"], + input[type="reset"], + input[type="button"], + button, + .button { + width: 100%; + + &.icon { + &:before { + margin-left: -0.5rem; + } + } + } + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_box.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_box.scss new file mode 100644 index 0000000..bdb2523 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_box.scss @@ -0,0 +1,26 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Box */ + + .box { + border-radius: _size(border-radius); + border: solid _size(border-width) _palette(border); + margin-bottom: _size(element-margin); + padding: 1.5em; + + > :last-child, + > :last-child > :last-child, + > :last-child > :last-child > :last-child { + margin-bottom: 0; + } + + &.alt { + border: 0; + border-radius: 0; + padding: 0; + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_button.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_button.scss new file mode 100644 index 0000000..effe178 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_button.scss @@ -0,0 +1,106 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Button */ + + input[type="submit"], + input[type="reset"], + input[type="button"], + button, + .button { + @include vendor('appearance', 'none'); + @include vendor('transition', ( + 'border-color #{_duration(transition)} ease' + )); + background-color: transparent; + border: solid 1px !important; + border-color: _palette(border) !important; + border-radius: 3em; + color: _palette(fg-bold) !important; + cursor: pointer; + display: inline-block; + font-size: 0.6em; + font-weight: _font(weight-bold); + height: calc(4.75em + 2px); + letter-spacing: _font(kerning-alt); + line-height: 4.75em; + outline: 0; + padding: 0 3.75em; + position: relative; + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + + &:after { + @include vendor('transform', 'scale(0.25)'); + @include vendor('pointer-events', 'none'); + @include vendor('transition', ( + 'opacity #{_duration(transition)} ease', + 'transform #{_duration(transition)} ease' + )); + background: _palette(fg-bold); + border-radius: 3em; + content: ''; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + } + + &.icon { + &:before { + margin-right: 0.75em; + } + } + + &.fit { + width: 100%; + } + + &.small { + font-size: 0.4em; + } + + &.large { + font-size: 0.8em; + } + + &.primary { + background-color: _palette(fg-bold); + color: _palette(bg) !important; + + &:after { + display: none; + } + } + + &.disabled, + &:disabled { + cursor: default; + opacity: 0.5; + @include vendor('pointer-events', 'none'); + } + + &:hover { + border-color: _palette(fg) !important; + + &:after { + opacity: 0.05; + @include vendor('transform', 'scale(1)'); + } + + &:active { + border-color: _palette(fg-bold) !important; + + &:after { + opacity: 0.1; + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_contact.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_contact.scss new file mode 100644 index 0000000..968279c --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_contact.scss @@ -0,0 +1,21 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Contact */ + + ul.contact { + list-style: none; + padding: 0; + + > li { + padding: 0; + margin: 1.5em 0 0 0; + + &:first-child { + margin-top: 0; + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_features.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_features.scss new file mode 100644 index 0000000..c045a52 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_features.scss @@ -0,0 +1,98 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Features */ + + .features { + @include vendor('display', 'flex'); + @include vendor('flex-wrap', 'wrap'); + border-radius: _size(border-radius); + border: solid 1px _palette(border); + background: _palette(border-bg); + margin: 0 0 _size(element-margin) 0; + + section { + @include padding(3em, 3em, (0.5em, 0, 0, 4em)); + width: 50%; + border-top: solid 1px _palette(border); + position: relative; + + &:nth-child(-n + 2) { + border-top-width: 0; + } + + &:nth-child(2n) { + border-left: solid 1px _palette(border); + } + + .icon { + @include vendor('transition', ( + 'opacity #{_duration(activation) * 0.5} ease', + 'transform #{_duration(activation) * 0.5} ease' + )); + @include vendor('transition-delay', '1s'); + @include vendor('transform', 'scale(1)'); + position: absolute; + left: 3em; + top: 3em; + opacity: 1; + } + + @for $i from 1 through _misc(max-features) { + &:nth-child(#{$i}) { + .icon { + @include vendor('transition-delay', '#{(_duration(transition) * 0.75 * $i)}'); + } + } + } + } + + &.inactive { + section { + .icon { + @include vendor('transform', 'scale(0.5)'); + opacity: 0; + } + } + } + + @include breakpoint('<=medium') { + display: block; + + section { + border-top-width: 1px !important; + border-left-width: 0 !important; + width: 100%; + + &:first-child { + border-top-width: 0 !important; + } + } + } + + @include breakpoint('<=small') { + section { + @include padding(2em, 1.5em, (0.5em, 0, 0, 4em)); + + .icon { + left: 1.5em; + top: 2em; + } + } + } + + @include breakpoint('<=xsmall') { + section { + @include padding(2em, 1.5em, (0, 0, 0, 0)); + + .icon { + left: 0; + position: relative; + top: 0; + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_form.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_form.scss new file mode 100644 index 0000000..1fb4177 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_form.scss @@ -0,0 +1,237 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Form */ + + form { + margin: 0 0 _size(element-margin) 0; + + > :last-child { + margin-bottom: 0; + } + + > .fields { + $gutter: (_size(element-margin) * 0.75); + + @include vendor('display', 'flex'); + @include vendor('flex-wrap', 'wrap'); + width: calc(100% + #{$gutter * 2}); + margin: ($gutter * -1) 0 _size(element-margin) ($gutter * -1); + + > .field { + @include vendor('flex-grow', '0'); + @include vendor('flex-shrink', '0'); + padding: $gutter 0 0 $gutter; + width: calc(100% - #{$gutter * 1}); + + &.half { + width: calc(50% - #{$gutter * 0.5}); + } + + &.third { + width: calc(#{100% / 3} - #{$gutter * (1 / 3)}); + } + + &.quarter { + width: calc(25% - #{$gutter * 0.25}); + } + } + } + + @include breakpoint('<=xsmall') { + > .fields { + $gutter: (_size(element-margin) * 0.75); + + width: calc(100% + #{$gutter * 2}); + margin: ($gutter * -1) 0 _size(element-margin) ($gutter * -1); + + > .field { + padding: $gutter 0 0 $gutter; + width: calc(100% - #{$gutter * 1}); + + &.half { + width: calc(100% - #{$gutter * 1}); + } + + &.third { + width: calc(100% - #{$gutter * 1}); + } + + &.quarter { + width: calc(100% - #{$gutter * 1}); + } + } + } + } + } + + label { + color: _palette(fg-bold); + font-weight: _font(weight-bold); + line-height: 1.5; + margin: 0 0 (_size(element-margin) * 0.35) 0; + display: block; + font-size: 1.1em; + } + + input[type="text"], + input[type="password"], + input[type="email"], + input[type="tel"], + select, + textarea { + @include vendor('appearance', 'none'); + background: _palette(border-bg); + border-radius: _size(border-radius); + border: none; + border: solid _size(border-width) _palette(border); + color: inherit; + display: block; + outline: 0; + padding: 0 1em; + text-decoration: none; + width: 100%; + + &:invalid { + box-shadow: none; + } + + &:focus { + border-color: _palette(fg-bold); + box-shadow: 0 0 0 _size(border-width) _palette(fg-bold); + } + } + + select { + background-image: svg-url(""); + background-size: 1.25rem; + background-repeat: no-repeat; + background-position: calc(100% - 1rem) center; + height: _size(element-height); + padding-right: _size(element-height); + text-overflow: ellipsis; + + option { + color: _palette(fg-bold); + background: _palette(bg); + } + + &:focus { + &::-ms-value { + background-color: transparent; + } + } + + &::-ms-expand { + display: none; + } + } + + input[type="text"], + input[type="password"], + input[type="email"], + select { + height: _size(element-height); + } + + textarea { + padding: 0.75em 1em; + + body.is-ie & { + min-height: 10em; + } + } + + input[type="checkbox"], + input[type="radio"], { + @include vendor('appearance', 'none'); + display: block; + float: left; + margin-right: -2em; + opacity: 0; + width: 1em; + z-index: -1; + + & + label { + @include icon(false, solid); + color: _palette(fg); + cursor: pointer; + display: inline-block; + font-size: 1em; + font-weight: _font(weight); + padding-left: (_size(element-height) * 0.6) + 0.75em; + padding-right: 0.75em; + position: relative; + + &:before { + background: _palette(border-bg); + border-radius: _size(border-radius); + border: solid _size(border-width) _palette(border); + content: ''; + display: inline-block; + font-size: 0.8em; + height: (_size(element-height) * 0.75); + left: 0; + line-height: (_size(element-height) * 0.75); + position: absolute; + text-align: center; + top: 0; + width: (_size(element-height) * 0.75); + } + } + + &:checked + label { + &:before { + background: _palette(fg-bold); + border-color: _palette(fg-bold); + color: _palette(accent3); + content: '\f00c'; + } + } + + &:focus + label { + &:before { + border-color: _palette(fg-bold); + box-shadow: 0 0 0 _size(border-width) _palette(fg-bold); + } + } + } + + input[type="checkbox"] { + & + label { + &:before { + border-radius: _size(border-radius); + } + } + } + + input[type="radio"] { + & + label { + &:before { + border-radius: 100%; + } + } + } + + ::-webkit-input-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } + + :-moz-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } + + ::-moz-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } + + :-ms-input-placeholder { + color: _palette(fg-light) !important; + opacity: 1.0; + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_icon.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_icon.scss new file mode 100644 index 0000000..a04acc9 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_icon.scss @@ -0,0 +1,73 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Icon */ + + .icon { + @include icon; + border-bottom: none; + position: relative; + + > .label { + display: none; + } + + &:before { + line-height: inherit; + } + + &.solid { + &:before { + font-weight: 900; + } + } + + &.brands { + &:before { + font-family: 'Font Awesome 5 Brands'; + } + } + + &.major { + width: 2.5em; + height: 2.5em; + display: block; + background: _palette(fg-bold); + border-radius: 100%; + color: _palette(bg); + text-align: center; + line-height: 2.5em; + margin: 0 0 (_size(element-margin) * 0.65) 0; + + &:before { + font-size: 1.25em; + + .wrapper.style1 & { + color: _palette(accent1); + } + + .wrapper.style1-alt & { + color: _palette(accent1-alt); + } + + .wrapper.style2 & { + color: _palette(accent2); + } + + .wrapper.style2-alt & { + color: _palette(accent2-alt); + } + + .wrapper.style3 & { + color: _palette(accent3); + } + + .wrapper.style3-alt & { + color: _palette(accent3-alt); + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_icons.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_icons.scss new file mode 100644 index 0000000..a52f7fb --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_icons.scss @@ -0,0 +1,30 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Icons */ + + ul.icons { + cursor: default; + list-style: none; + padding-left: 0; + + li { + display: inline-block; + padding: 0 0.75em 0 0; + + &:last-child { + padding-right: 0; + } + + > a, > span { + border: 0; + + .label { + display: none; + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_image.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_image.scss new file mode 100644 index 0000000..30df35e --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_image.scss @@ -0,0 +1,60 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Image */ + + .image { + border-radius: _size(border-radius); + border: 0; + display: inline-block; + position: relative; + + img { + border-radius: _size(border-radius); + display: block; + } + + &.left, + &.right { + max-width: 40%; + + img { + width: 100%; + } + } + + &.left { + float: left; + margin: 0 1.5em 1em 0; + top: 0.25em; + } + + &.right { + float: right; + margin: 0 0 1em 1.5em; + top: 0.25em; + } + + &.fit { + display: block; + margin: 0 0 _size(element-margin) 0; + width: 100%; + + img { + width: 100%; + } + } + + &.main { + display: block; + margin: 0 0 (_size(element-margin) * 1.5) 0; + width: 100%; + + img { + width: 100%; + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_list.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_list.scss new file mode 100644 index 0000000..e2e296c --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_list.scss @@ -0,0 +1,56 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* List */ + + ol { + list-style: decimal; + margin: 0 0 _size(element-margin) 0; + padding-left: 1.25em; + + li { + padding-left: 0.25em; + } + } + + ul { + list-style: disc; + margin: 0 0 _size(element-margin) 0; + padding-left: 1em; + + li { + padding-left: 0.5em; + } + + &.alt { + list-style: none; + padding-left: 0; + + li { + border-top: solid _size(border-width) _palette(border); + padding: 0.5em 0; + + &:first-child { + border-top: 0; + padding-top: 0; + } + } + } + } + + dl { + margin: 0 0 _size(element-margin) 0; + + dt { + display: block; + font-weight: _font(weight-bold); + margin: 0 0 (_size(element-margin) * 0.5) 0; + } + + dd { + margin-left: _size(element-margin); + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_menu.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_menu.scss new file mode 100644 index 0000000..9bbc593 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_menu.scss @@ -0,0 +1,36 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Menu */ + + ul.menu { + list-style: none; + padding: 0; + + > li { + border-left: solid 1px _palette(border); + display: inline-block; + line-height: 1; + margin-left: 1.5em; + padding: 0 0 0 1.5em; + + &:first-child { + border-left: 0; + margin: 0; + padding-left: 0; + } + } + + @include breakpoint('<=xsmall') { + > li { + border-left: 0; + display: block; + line-height: inherit; + margin: 0.5em 0 0 0; + padding-left: 0; + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_row.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_row.scss new file mode 100644 index 0000000..d285054 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_row.scss @@ -0,0 +1,31 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Row */ + + .row { + @include html-grid(1.5em); + + @include breakpoint('<=xlarge') { + @include html-grid(1.5em, 'xlarge'); + } + + @include breakpoint('<=large') { + @include html-grid(1.5em, 'large'); + } + + @include breakpoint('<=medium') { + @include html-grid(1.5em, 'medium'); + } + + @include breakpoint('<=small') { + @include html-grid(1.5em, 'small'); + } + + @include breakpoint('<=xsmall') { + @include html-grid(1.5em, 'xsmall'); + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_section.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_section.scss new file mode 100644 index 0000000..3a9d562 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_section.scss @@ -0,0 +1,41 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Section/Article */ + + section, article { + &.special { + text-align: center; + } + } + + header { + p { + color: _palette(fg-light); + position: relative; + margin: 0 0 (_size(element-margin) * 0.75) 0; + } + + h2 + p { + font-size: 1.25em; + margin-top: (_size(element-margin) * -0.5); + line-height: 1.5em; + } + + h3 + p { + font-size: 1.1em; + margin-top: (_size(element-margin) * -0.4); + line-height: 1.5em; + } + + h4 + p, + h5 + p, + h6 + p { + font-size: 0.9em; + margin-top: (_size(element-margin) * -0.3); + line-height: 1.5em; + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_split.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_split.scss new file mode 100644 index 0000000..cbc2c4e --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_split.scss @@ -0,0 +1,91 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Split */ + + .split { + @include vendor('display', 'flex'); + + > * { + width: calc(50% - 2.5em); + } + + > :nth-child(2n - 1) { + padding-right: 2.5em; + border-right: solid 1px _palette(border); + } + + > :nth-child(2n) { + padding-left: 2.5em; + } + + &.style1 { + > :nth-child(2n - 1) { + width: calc(66.66666% - 2.5em); + } + + > :nth-child(2n) { + width: calc(33.33333% - 2.5em); + } + } + + @include breakpoint('<=xlarge') { + > * { + width: calc(50% - 2em); + } + + > :nth-child(2n - 1) { + padding-right: 2em; + } + + > :nth-child(2n) { + padding-left: 2em; + } + + &.style1 { + > :nth-child(2n - 1) { + width: calc(66.66666% - 2em); + } + + > :nth-child(2n) { + width: calc(33.33333% - 2em); + } + } + } + + @include breakpoint('<=medium') { + display: block; + + > * { + border-top: solid 1px _palette(border); + margin: 4em 0 0 0; + padding: 4em 0 0 0; + width: 100% !important; + } + + > :nth-child(2n - 1) { + border-right: 0; + padding-right: 0; + } + + > :nth-child(2n) { + padding-left: 0; + } + + > :first-child { + border-top: 0; + margin-top: 0; + padding-top: 0; + } + } + + @include breakpoint('<=small') { + > * { + margin: 3em 0 0 0; + padding: 3em 0 0 0; + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_spotlights.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_spotlights.scss new file mode 100644 index 0000000..74e5ecc --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_spotlights.scss @@ -0,0 +1,130 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Spotlights */ + + .spotlights { + > section { + @include vendor('display', 'flex'); + @include vendor('flex-direction', 'row'); + min-height: 22.5em; + + body.is-ie & { + min-height: 0; + } + + > .image { + background-position: center center; + background-size: cover; + border-radius: 0; + display: block; + position: relative; + width: 25em; + + img { + border-radius: 0; + display: block; + } + + &:before { + @include vendor('transition', 'opacity #{_duration(activation)} ease'); + background: transparentize(_palette(bg), 0.1); + content: ''; + display: block; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + } + } + + > .content { + @include padding(4em, 5em); + @include vendor('display', 'flex'); + @include vendor('flex-direction', 'column'); + @include vendor('justify-content', 'center'); + width: #{_size(inner-width) - 25em}; + -ms-flex: 1; + + > .inner { + @include vendor('transform', 'translateX(0) translateY(0)'); + @include vendor('transition', ( + 'opacity #{_duration(activation)} ease', + 'transform #{_duration(activation)} ease' + )); + opacity: 1; + } + } + + &:nth-child(1) { + } + + &:nth-child(2) { + background-color: rgba(0,0,0,0.05); + } + + &:nth-child(3) { + background-color: rgba(0,0,0,0.1); + } + + &.inactive, + body.is-preload & { + > .image { + &:before { + opacity: 1; + } + } + + > .content { + > .inner { + @include vendor('transform', 'translateX(-1em)'); + opacity: 0; + } + } + } + + @include breakpoint('<=xlarge') { + > .content { + @include padding(4em, 4em); + } + } + + @include breakpoint('<=medium') { + display: block; + + > .image { + width: 100%; + height: 50vh; + } + + > .content { + width: 100%; + } + + &.inactive, + body.is-preload & { + > .content { + > .inner { + @include vendor('transform', 'translateY(1em)'); + } + } + } + } + + @include breakpoint('<=small') { + > .image { + height: 50vh; + min-height: 15em; + } + + > .content { + @include padding(3em, 2em); + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_table.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_table.scss new file mode 100644 index 0000000..28ebe22 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_table.scss @@ -0,0 +1,81 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Table */ + + .table-wrapper { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + } + + table { + margin: 0 0 _size(element-margin) 0; + width: 100%; + + tbody { + tr { + border: solid _size(border-width) _palette(border); + border-left: 0; + border-right: 0; + + &:nth-child(2n + 1) { + background-color: _palette(border-bg); + } + } + } + + td { + padding: 0.75em 0.75em; + } + + th { + color: _palette(fg-bold); + font-size: 1em; + font-weight: _font(weight-bold); + padding: 0 0.75em 0.75em 0.75em; + text-align: left; + } + + thead { + border-bottom: solid (_size(border-width) * 2) _palette(border); + } + + tfoot { + border-top: solid (_size(border-width) * 2) _palette(border); + } + + &.alt { + border-collapse: separate; + + tbody { + tr { + td { + border: solid _size(border-width) _palette(border); + border-left-width: 0; + border-top-width: 0; + + &:first-child { + border-left-width: _size(border-width); + } + } + + &:first-child { + td { + border-top-width: _size(border-width); + } + } + } + } + + thead { + border-bottom: 0; + } + + tfoot { + border-top: 0; + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/components/_wrapper.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_wrapper.scss new file mode 100644 index 0000000..122c61c --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/components/_wrapper.scss @@ -0,0 +1,139 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Wrapper */ + + .wrapper { + position: relative; + + > .inner { + @include padding(5em, 5em); + max-width: 100%; + width: _size(inner-width); + + @include breakpoint('<=xlarge') { + @include padding(4em, 4em); + } + + @include breakpoint('<=large') { + width: 100%; + } + + @include breakpoint('<=small') { + @include padding(3em, 2em); + } + } + + &.alt { + background-color: _palette(bg-alt); + } + + &.style1 { + background-color: _palette(accent1); + } + + &.style1-alt { + background-color: _palette(accent1-alt); + } + + &.style2 { + background-color: _palette(accent2); + } + + &.style2-alt { + background-color: _palette(accent2-alt); + } + + &.style3 { + background-color: _palette(accent3); + } + + &.style3-alt { + background-color: _palette(accent3-alt); + } + + &.fullscreen { + @include vendor('display', 'flex'); + @include vendor('flex-direction', 'column'); + @include vendor('justify-content', 'center'); + min-height: 100vh; + + body.is-ie & { + height: 100vh; + } + + @include breakpoint('<=large') { + min-height: calc(100vh - 2.5em); + + body.is-ie & { + height: calc(100vh - 2.5em); + } + } + + @include breakpoint('<=small') { + padding: 2em 0; + min-height: 0; + + body.is-ie & { + height: auto; + } + } + } + + &.fade-up { + > .inner { + @include vendor('transform', 'translateY(0)'); + @include vendor('transition', ( + 'opacity #{_duration(activation)} ease', + 'transform #{_duration(activation)} ease' + )); + opacity: 1.0; + } + + &.inactive, + body.is-preload & { + > .inner { + opacity: 0; + @include vendor('transform', 'translateY(1em)'); + } + } + } + + &.fade-down { + > .inner { + @include vendor('transform', 'translateY(0)'); + @include vendor('transition', ( + 'opacity #{_duration(activation)} ease', + 'transform #{_duration(activation)} ease' + )); + opacity: 1.0; + } + + &.inactive, + body.is-preload & { + > .inner { + opacity: 0; + @include vendor('transform', 'translateY(-1em)'); + } + } + } + + &.fade { + > .inner { + @include vendor('transition', ( + 'opacity #{_duration(activation)} ease' + )); + opacity: 1.0; + } + + &.inactive, + body.is-preload & { + > .inner { + opacity: 0; + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_footer.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_footer.scss new file mode 100644 index 0000000..1f516ab --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_footer.scss @@ -0,0 +1,38 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Footer */ + + #footer { + #sidebar + #wrapper + & { + margin-left: _size(sidebar-width); + + @include breakpoint('<=large') { + margin-left: 0; + } + } + + > .inner { + a { + border-bottom-color: _palette(border); + + &:hover { + border-bottom-color: transparent; + } + } + + .menu { + font-size: 0.8em; + color: _palette(border); + } + } + + #header + #wrapper + & { + > .inner { + margin: 0 auto; + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_header.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_header.scss new file mode 100644 index 0000000..05ec781 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_header.scss @@ -0,0 +1,92 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Header */ + + #header { + @include vendor('display', 'flex'); + background-color: _palette(accent1); + cursor: default; + padding: 1.75em 2em; + + > .title { + border: 0; + color: _palette(fg-bold); + display: block; + font-size: 1.25em; + font-weight: _font(weight-bold); + } + + > nav { + @include vendor('flex', '1'); + text-align: right; + + > ul { + margin: 0; + padding: 0; + + > li { + display: inline-block; + margin-left: 1.75em; + padding: 0; + vertical-align: middle; + + &:first-child { + margin-left: 0; + } + + a { + border: 0; + color: _palette(fg-light); + display: inline-block; + font-size: 0.6em; + font-weight: _font(weight-bold); + letter-spacing: _font(kerning-alt); + text-transform: uppercase; + + &:hover { + color: _palette(fg); + } + + &.active { + color: _palette(fg-bold); + } + } + } + } + } + + @include breakpoint('<=small') { + padding: 1em 2em; + } + + @include breakpoint('<=xsmall') { + display: block; + padding: 0 2em; + text-align: left; + + .title { + font-size: 1.25em; + padding: 1em 0; + } + + > nav { + border-top: solid 1px _palette(border); + text-align: inherit; + + > ul { + > li { + margin-left: 1.5em; + + a { + height: 6em; + line-height: 6em; + } + } + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_intro.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_intro.scss new file mode 100644 index 0000000..10c3e42 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_intro.scss @@ -0,0 +1,33 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Intro */ + + #intro { + background-attachment: fixed; + background-image: url('images/intro.svg'); + background-position: top right; + background-repeat: no-repeat; + background-size: 100% 100%; + + p { + font-size: 1.25em; + + @include breakpoint('<=medium') { + br { + display: none; + } + } + + @include breakpoint('<=small') { + font-size: 1em; + } + } + + @include breakpoint('<=large') { + background-attachment: scroll; + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_sidebar.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_sidebar.scss new file mode 100644 index 0000000..efc8fcb --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_sidebar.scss @@ -0,0 +1,185 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Sidebar */ + + #sidebar { + @include padding(2.5em, 2.5em); + background: _palette(bg); + cursor: default; + height: 100vh; + left: 0; + overflow-x: hidden; + overflow-y: auto; + position: fixed; + text-align: right; + top: 0; + width: _size(sidebar-width); + z-index: _misc(z-index-base); + + > .inner { + @include vendor('display', 'flex'); + @include vendor('flex-direction', 'column'); + @include vendor('justify-content', 'center'); + @include vendor('transform', 'translateY(0)'); + @include vendor('transition', ( + 'opacity #{_duration(activation)} ease', + )); + min-height: 100%; + opacity: 1; + width: 100%; + + body.is-ie & { + height: 100%; + } + } + + nav { + > ul { + list-style: none; + padding: 0; + + > li { + @include vendor('transform', 'translateY(0)'); + @include vendor('transition', ( + 'opacity #{_duration(activation) * 0.15} ease', + 'transform #{_duration(activation) * 0.75} ease' + )); + margin: 1.5em 0 0 0; + opacity: 1; + padding: 0; + position: relative; + + &:first-child { + margin: 0; + } + + @for $i from 1 through _misc(max-sidebar-links) { + &:nth-child(#{$i}) { + @include vendor('transition-delay', '#{(_duration(activation) * 0.2 * $i) + (_duration(activation) * 0.25)}'); + } + } + } + } + + a { + @include vendor('transition', 'color #{_duration(transition)} ease'); + border: 0; + color: _palette(fg-light); + display: block; + font-size: 0.6em; + font-weight: _font(weight-bold); + letter-spacing: _font(kerning-alt); + line-height: 1.75; + outline: 0; + padding: 1.35em 0; + position: relative; + text-decoration: none; + text-transform: uppercase; + + &:before, + &:after { + border-radius: 0.2em; + bottom: 0; + content: ''; + height: 0.2em; + position: absolute; + right: 0; + width: 100%; + } + + &:before { + background: lighten(_palette(bg), 5); + } + + &:after { + @include vendor('background-image', 'linear-gradient(to right, #{_palette(accent1)}, #{_palette(accent3)})'); + @include vendor('transition', 'max-width #{_duration(transition)} ease'); + max-width: 0; + } + + &:hover { + color: _palette(fg); + } + + &.active { + color: _palette(fg-bold); + + &:after { + max-width: 100%; + } + } + } + } + + body.is-preload & { + > .inner { + opacity: 0; + } + + nav { + ul { + li { + @include vendor('transform', 'translateY(2em)'); + opacity: 0; + } + } + } + } + + @include breakpoint('<=large') { + height: _size(sidebar-height); + left: 0; + line-height: _size(sidebar-height); + overflow: hidden; + padding: 0; + text-align: center; + top: 0; + width: 100%; + + > .inner { + @include vendor('flex-direction', 'row'); + @include vendor('align-items', 'stretch'); + height: inherit; + line-height: inherit; + } + + nav { + height: inherit; + line-height: inherit; + + ul { + @include vendor('display', 'flex'); + height: inherit; + line-height: inherit; + margin: 0; + + li { + display: block; + height: inherit; + line-height: inherit; + margin: 0 0 0 2em; + padding: 0; + } + } + + a { + height: inherit; + line-height: inherit; + padding: 0; + + &:after { + background-image: none; + background-color: _palette(accent3); + } + } + } + } + + @include breakpoint('<=small') { + display: none; + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_wrapper.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_wrapper.scss new file mode 100644 index 0000000..f8a15b2 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/layout/_wrapper.scss @@ -0,0 +1,30 @@ +/// +/// Hyperspace by HTML5 UP +/// html5up.net | @ajlkn +/// Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +/// + +/* Wrapper (main) */ + + #wrapper { + #sidebar + & { + margin-left: _size(sidebar-width); + + @include breakpoint('<=large') { + margin-left: 0; + padding-top: _size(sidebar-height); + } + + @include breakpoint('<=small') { + padding-top: 0; + } + } + + #header + & { + > .wrapper { + > .inner { + margin: 0 auto; + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_breakpoints.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_breakpoints.scss new file mode 100644 index 0000000..3769328 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_breakpoints.scss @@ -0,0 +1,223 @@ +// breakpoints.scss v1.0 | @ajlkn | MIT licensed */ + +// Vars. + + /// Breakpoints. + /// @var {list} + $breakpoints: () !global; + +// Mixins. + + /// Sets breakpoints. + /// @param {map} $x Breakpoints. + @mixin breakpoints($x: ()) { + $breakpoints: $x !global; + } + + /// Wraps @content in a @media block targeting a specific orientation. + /// @param {string} $orientation Orientation. + @mixin orientation($orientation) { + @media screen and (orientation: #{$orientation}) { + @content; + } + } + + /// Wraps @content in a @media block using a given query. + /// @param {string} $query Query. + @mixin breakpoint($query: null) { + + $breakpoint: null; + $op: null; + $media: null; + + // Determine operator, breakpoint. + + // Greater than or equal. + @if (str-slice($query, 0, 2) == '>=') { + + $op: 'gte'; + $breakpoint: str-slice($query, 3); + + } + + // Less than or equal. + @elseif (str-slice($query, 0, 2) == '<=') { + + $op: 'lte'; + $breakpoint: str-slice($query, 3); + + } + + // Greater than. + @elseif (str-slice($query, 0, 1) == '>') { + + $op: 'gt'; + $breakpoint: str-slice($query, 2); + + } + + // Less than. + @elseif (str-slice($query, 0, 1) == '<') { + + $op: 'lt'; + $breakpoint: str-slice($query, 2); + + } + + // Not. + @elseif (str-slice($query, 0, 1) == '!') { + + $op: 'not'; + $breakpoint: str-slice($query, 2); + + } + + // Equal. + @else { + + $op: 'eq'; + $breakpoint: $query; + + } + + // Build media. + @if ($breakpoint and map-has-key($breakpoints, $breakpoint)) { + + $a: map-get($breakpoints, $breakpoint); + + // Range. + @if (type-of($a) == 'list') { + + $x: nth($a, 1); + $y: nth($a, 2); + + // Max only. + @if ($x == null) { + + // Greater than or equal (>= 0 / anything) + @if ($op == 'gte') { + $media: 'screen'; + } + + // Less than or equal (<= y) + @elseif ($op == 'lte') { + $media: 'screen and (max-width: ' + $y + ')'; + } + + // Greater than (> y) + @elseif ($op == 'gt') { + $media: 'screen and (min-width: ' + ($y + 1) + ')'; + } + + // Less than (< 0 / invalid) + @elseif ($op == 'lt') { + $media: 'screen and (max-width: -1px)'; + } + + // Not (> y) + @elseif ($op == 'not') { + $media: 'screen and (min-width: ' + ($y + 1) + ')'; + } + + // Equal (<= y) + @else { + $media: 'screen and (max-width: ' + $y + ')'; + } + + } + + // Min only. + @else if ($y == null) { + + // Greater than or equal (>= x) + @if ($op == 'gte') { + $media: 'screen and (min-width: ' + $x + ')'; + } + + // Less than or equal (<= inf / anything) + @elseif ($op == 'lte') { + $media: 'screen'; + } + + // Greater than (> inf / invalid) + @elseif ($op == 'gt') { + $media: 'screen and (max-width: -1px)'; + } + + // Less than (< x) + @elseif ($op == 'lt') { + $media: 'screen and (max-width: ' + ($x - 1) + ')'; + } + + // Not (< x) + @elseif ($op == 'not') { + $media: 'screen and (max-width: ' + ($x - 1) + ')'; + } + + // Equal (>= x) + @else { + $media: 'screen and (min-width: ' + $x + ')'; + } + + } + + // Min and max. + @else { + + // Greater than or equal (>= x) + @if ($op == 'gte') { + $media: 'screen and (min-width: ' + $x + ')'; + } + + // Less than or equal (<= y) + @elseif ($op == 'lte') { + $media: 'screen and (max-width: ' + $y + ')'; + } + + // Greater than (> y) + @elseif ($op == 'gt') { + $media: 'screen and (min-width: ' + ($y + 1) + ')'; + } + + // Less than (< x) + @elseif ($op == 'lt') { + $media: 'screen and (max-width: ' + ($x - 1) + ')'; + } + + // Not (< x and > y) + @elseif ($op == 'not') { + $media: 'screen and (max-width: ' + ($x - 1) + '), screen and (min-width: ' + ($y + 1) + ')'; + } + + // Equal (>= x and <= y) + @else { + $media: 'screen and (min-width: ' + $x + ') and (max-width: ' + $y + ')'; + } + + } + + } + + // String. + @else { + + // Missing a media type? Prefix with "screen". + @if (str-slice($a, 0, 1) == '(') { + $media: 'screen and ' + $a; + } + + // Otherwise, use as-is. + @else { + $media: $a; + } + + } + + } + + // Output. + @media #{$media} { + @content; + } + + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_functions.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_functions.scss new file mode 100644 index 0000000..ec6a29f --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_functions.scss @@ -0,0 +1,90 @@ +/// Removes a specific item from a list. +/// @author Hugo Giraudel +/// @param {list} $list List. +/// @param {integer} $index Index. +/// @return {list} Updated list. +@function remove-nth($list, $index) { + + $result: null; + + @if type-of($index) != number { + @warn "$index: #{quote($index)} is not a number for `remove-nth`."; + } + @else if $index == 0 { + @warn "List index 0 must be a non-zero integer for `remove-nth`."; + } + @else if abs($index) > length($list) { + @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`."; + } + @else { + + $result: (); + $index: if($index < 0, length($list) + $index + 1, $index); + + @for $i from 1 through length($list) { + + @if $i != $index { + $result: append($result, nth($list, $i)); + } + + } + + } + + @return $result; + +} + +/// Gets a value from a map. +/// @author Hugo Giraudel +/// @param {map} $map Map. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function val($map, $keys...) { + + @if nth($keys, 1) == null { + $keys: remove-nth($keys, 1); + } + + @each $key in $keys { + $map: map-get($map, $key); + } + + @return $map; + +} + +/// Gets a duration value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _duration($keys...) { + @return val($duration, $keys...); +} + +/// Gets a font value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _font($keys...) { + @return val($font, $keys...); +} + +/// Gets a misc value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _misc($keys...) { + @return val($misc, $keys...); +} + +/// Gets a palette value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _palette($keys...) { + @return val($palette, $keys...); +} + +/// Gets a size value. +/// @param {string} $keys Key(s). +/// @return {string} Value. +@function _size($keys...) { + @return val($size, $keys...); +} diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_html-grid.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_html-grid.scss new file mode 100644 index 0000000..fbf0ac9 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_html-grid.scss @@ -0,0 +1,149 @@ +// html-grid.scss v1.0 | @ajlkn | MIT licensed */ + +// Mixins. + + /// Initializes the current element as an HTML grid. + /// @param {mixed} $gutters Gutters (either a single number to set both column/row gutters, or a list to set them individually). + /// @param {mixed} $suffix Column class suffix (optional; either a single suffix or a list). + @mixin html-grid($gutters: 1.5em, $suffix: '') { + + // Initialize. + $cols: 12; + $multipliers: 0, 0.25, 0.5, 1, 1.50, 2.00; + $unit: 100% / $cols; + + // Suffixes. + $suffixes: null; + + @if (type-of($suffix) == 'list') { + $suffixes: $suffix; + } + @else { + $suffixes: ($suffix); + } + + // Gutters. + $guttersCols: null; + $guttersRows: null; + + @if (type-of($gutters) == 'list') { + + $guttersCols: nth($gutters, 1); + $guttersRows: nth($gutters, 2); + + } + @else { + + $guttersCols: $gutters; + $guttersRows: 0; + + } + + // Row. + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + align-items: stretch; + + // Columns. + > * { + box-sizing: border-box; + } + + // Gutters. + &.gtr-uniform { + > * { + > :last-child { + margin-bottom: 0; + } + } + } + + // Alignment. + &.aln-left { + justify-content: flex-start; + } + + &.aln-center { + justify-content: center; + } + + &.aln-right { + justify-content: flex-end; + } + + &.aln-top { + align-items: flex-start; + } + + &.aln-middle { + align-items: center; + } + + &.aln-bottom { + align-items: flex-end; + } + + // Step through suffixes. + @each $suffix in $suffixes { + + // Suffix. + @if ($suffix != '') { + $suffix: '-' + $suffix; + } + @else { + $suffix: ''; + } + + // Row. + + // Important. + > .imp#{$suffix} { + order: -1; + } + + // Columns, offsets. + @for $i from 1 through $cols { + > .col-#{$i}#{$suffix} { + width: $unit * $i; + } + + > .off-#{$i}#{$suffix} { + margin-left: $unit * $i; + } + } + + // Step through multipliers. + @each $multiplier in $multipliers { + + // Gutters. + $class: null; + + @if ($multiplier != 1) { + $class: '.gtr-' + ($multiplier * 100); + } + + &#{$class} { + margin-top: ($guttersRows * $multiplier * -1); + margin-left: ($guttersCols * $multiplier * -1); + + > * { + padding: ($guttersRows * $multiplier) 0 0 ($guttersCols * $multiplier); + } + + // Uniform. + &.gtr-uniform { + margin-top: $guttersCols * $multiplier * -1; + + > * { + padding-top: $guttersCols * $multiplier; + } + } + + } + + } + + } + + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_mixins.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_mixins.scss new file mode 100644 index 0000000..612837d --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_mixins.scss @@ -0,0 +1,78 @@ +/// Makes an element's :before pseudoelement a FontAwesome icon. +/// @param {string} $content Optional content value to use. +/// @param {string} $category Optional category to use. +/// @param {string} $where Optional pseudoelement to target (before or after). +@mixin icon($content: false, $category: regular, $where: before) { + + text-decoration: none; + + &:#{$where} { + + @if $content { + content: $content; + } + + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + text-transform: none !important; + + @if ($category == brands) { + font-family: 'Font Awesome 5 Brands'; + } + @elseif ($category == solid) { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; + } + @else { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; + } + + } + +} + +/// Applies padding to an element, taking the current element-margin value into account. +/// @param {mixed} $tb Top/bottom padding. +/// @param {mixed} $lr Left/right padding. +/// @param {list} $pad Optional extra padding (in the following order top, right, bottom, left) +/// @param {bool} $important If true, adds !important. +@mixin padding($tb, $lr, $pad: (0,0,0,0), $important: null) { + + @if $important { + $important: '!important'; + } + + $x: 0.1em; + + @if unit(_size(element-margin)) == 'rem' { + $x: 0.1rem; + } + + padding: ($tb + nth($pad,1)) ($lr + nth($pad,2)) max($x, $tb - _size(element-margin) + nth($pad,3)) ($lr + nth($pad,4)) #{$important}; + +} + +/// Encodes a SVG data URL so IE doesn't choke (via codepen.io/jakob-e/pen/YXXBrp). +/// @param {string} $svg SVG data URL. +/// @return {string} Encoded SVG data URL. +@function svg-url($svg) { + + $svg: str-replace($svg, '"', '\''); + $svg: str-replace($svg, '%', '%25'); + $svg: str-replace($svg, '<', '%3C'); + $svg: str-replace($svg, '>', '%3E'); + $svg: str-replace($svg, '&', '%26'); + $svg: str-replace($svg, '#', '%23'); + $svg: str-replace($svg, '{', '%7B'); + $svg: str-replace($svg, '}', '%7D'); + $svg: str-replace($svg, ';', '%3B'); + + @return url("data:image/svg+xml;charset=utf8,#{$svg}"); + +} diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vars.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vars.scss new file mode 100644 index 0000000..61eb18c --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vars.scss @@ -0,0 +1,49 @@ +// Misc. + $misc: ( + z-index-base: 10000, + max-features: 20, + max-sidebar-links: 20 + ); + +// Duration. + $duration: ( + transition: 0.2s, + activation: 1s + ); + +// Size. + $size: ( + border-radius: 0.25em, + border-width: 1px, + element-height: 2.75em, + element-margin: 2em, + sidebar-width: 18em, + sidebar-height: 3.5em, // when <=large is active + inner-width: 75em + ); + +// Font. + $font: ( + family: (Arial, Helvetica, sans-serif), + family-fixed: ('Courier New', monospace), + weight: normal, + weight-bold: bold, + kerning-alt: 0.25em + ); + +// Palette. + $palette: ( + bg: #312450, + bg-alt: darken(#312450, 5), + fg: rgba(255,255,255,0.55), + fg-bold: #ffffff, + fg-light: rgba(255,255,255,0.35), + border: rgba(255,255,255,0.15), + border-bg: rgba(255,255,255,0.05), + accent1: #5e42a6, + accent1-alt: darken(#5e42a6, 10), + accent2: #5052b5, + accent2-alt: darken(#5052b5, 10), + accent3: #b74e91, + accent3-alt: darken(#b74e91, 10) + ); diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vendor.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vendor.scss new file mode 100644 index 0000000..8f2675c --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/libs/_vendor.scss @@ -0,0 +1,376 @@ +// vendor.scss v1.0 | @ajlkn | MIT licensed */ + +// Vars. + + /// Vendor prefixes. + /// @var {list} + $vendor-prefixes: ( + '-moz-', + '-webkit-', + '-ms-', + '' + ); + + /// Properties that should be vendorized. + /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org + /// @var {list} + $vendor-properties: ( + + // Animation. + 'animation', + 'animation-delay', + 'animation-direction', + 'animation-duration', + 'animation-fill-mode', + 'animation-iteration-count', + 'animation-name', + 'animation-play-state', + 'animation-timing-function', + + // Appearance. + 'appearance', + + // Backdrop filter. + 'backdrop-filter', + + // Background image options. + 'background-clip', + 'background-origin', + 'background-size', + + // Box sizing. + 'box-sizing', + + // Clip path. + 'clip-path', + + // Filter effects. + 'filter', + + // Flexbox. + 'align-content', + 'align-items', + 'align-self', + 'flex', + 'flex-basis', + 'flex-direction', + 'flex-flow', + 'flex-grow', + 'flex-shrink', + 'flex-wrap', + 'justify-content', + 'order', + + // Font feature. + 'font-feature-settings', + 'font-language-override', + 'font-variant-ligatures', + + // Font kerning. + 'font-kerning', + + // Fragmented borders and backgrounds. + 'box-decoration-break', + + // Grid layout. + 'grid-column', + 'grid-column-align', + 'grid-column-end', + 'grid-column-start', + 'grid-row', + 'grid-row-align', + 'grid-row-end', + 'grid-row-start', + 'grid-template-columns', + 'grid-template-rows', + + // Hyphens. + 'hyphens', + 'word-break', + + // Masks. + 'mask', + 'mask-border', + 'mask-border-outset', + 'mask-border-repeat', + 'mask-border-slice', + 'mask-border-source', + 'mask-border-width', + 'mask-clip', + 'mask-composite', + 'mask-image', + 'mask-origin', + 'mask-position', + 'mask-repeat', + 'mask-size', + + // Multicolumn. + 'break-after', + 'break-before', + 'break-inside', + 'column-count', + 'column-fill', + 'column-gap', + 'column-rule', + 'column-rule-color', + 'column-rule-style', + 'column-rule-width', + 'column-span', + 'column-width', + 'columns', + + // Object fit. + 'object-fit', + 'object-position', + + // Regions. + 'flow-from', + 'flow-into', + 'region-fragment', + + // Scroll snap points. + 'scroll-snap-coordinate', + 'scroll-snap-destination', + 'scroll-snap-points-x', + 'scroll-snap-points-y', + 'scroll-snap-type', + + // Shapes. + 'shape-image-threshold', + 'shape-margin', + 'shape-outside', + + // Tab size. + 'tab-size', + + // Text align last. + 'text-align-last', + + // Text decoration. + 'text-decoration-color', + 'text-decoration-line', + 'text-decoration-skip', + 'text-decoration-style', + + // Text emphasis. + 'text-emphasis', + 'text-emphasis-color', + 'text-emphasis-position', + 'text-emphasis-style', + + // Text size adjust. + 'text-size-adjust', + + // Text spacing. + 'text-spacing', + + // Transform. + 'transform', + 'transform-origin', + + // Transform 3D. + 'backface-visibility', + 'perspective', + 'perspective-origin', + 'transform-style', + + // Transition. + 'transition', + 'transition-delay', + 'transition-duration', + 'transition-property', + 'transition-timing-function', + + // Unicode bidi. + 'unicode-bidi', + + // User select. + 'user-select', + + // Writing mode. + 'writing-mode', + + ); + + /// Values that should be vendorized. + /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org + /// @var {list} + $vendor-values: ( + + // Cross fade. + 'cross-fade', + + // Element function. + 'element', + + // Filter function. + 'filter', + + // Flexbox. + 'flex', + 'inline-flex', + + // Grab cursors. + 'grab', + 'grabbing', + + // Gradients. + 'linear-gradient', + 'repeating-linear-gradient', + 'radial-gradient', + 'repeating-radial-gradient', + + // Grid layout. + 'grid', + 'inline-grid', + + // Image set. + 'image-set', + + // Intrinsic width. + 'max-content', + 'min-content', + 'fit-content', + 'fill', + 'fill-available', + 'stretch', + + // Sticky position. + 'sticky', + + // Transform. + 'transform', + + // Zoom cursors. + 'zoom-in', + 'zoom-out', + + ); + +// Functions. + + /// Removes a specific item from a list. + /// @author Hugo Giraudel + /// @param {list} $list List. + /// @param {integer} $index Index. + /// @return {list} Updated list. + @function remove-nth($list, $index) { + + $result: null; + + @if type-of($index) != number { + @warn "$index: #{quote($index)} is not a number for `remove-nth`."; + } + @else if $index == 0 { + @warn "List index 0 must be a non-zero integer for `remove-nth`."; + } + @else if abs($index) > length($list) { + @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`."; + } + @else { + + $result: (); + $index: if($index < 0, length($list) + $index + 1, $index); + + @for $i from 1 through length($list) { + + @if $i != $index { + $result: append($result, nth($list, $i)); + } + + } + + } + + @return $result; + + } + + /// Replaces a substring within another string. + /// @author Hugo Giraudel + /// @param {string} $string String. + /// @param {string} $search Substring. + /// @param {string} $replace Replacement. + /// @return {string} Updated string. + @function str-replace($string, $search, $replace: '') { + + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; + + } + + /// Replaces a substring within each string in a list. + /// @param {list} $strings List of strings. + /// @param {string} $search Substring. + /// @param {string} $replace Replacement. + /// @return {list} Updated list of strings. + @function str-replace-all($strings, $search, $replace: '') { + + @each $string in $strings { + $strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace)); + } + + @return $strings; + + } + +// Mixins. + + /// Wraps @content in vendorized keyframe blocks. + /// @param {string} $name Name. + @mixin keyframes($name) { + + @-moz-keyframes #{$name} { @content; } + @-webkit-keyframes #{$name} { @content; } + @-ms-keyframes #{$name} { @content; } + @keyframes #{$name} { @content; } + + } + + /// Vendorizes a declaration's property and/or value(s). + /// @param {string} $property Property. + /// @param {mixed} $value String/list of value(s). + @mixin vendor($property, $value) { + + // Determine if property should expand. + $expandProperty: index($vendor-properties, $property); + + // Determine if value should expand (and if so, add '-prefix-' placeholder). + $expandValue: false; + + @each $x in $value { + @each $y in $vendor-values { + @if $y == str-slice($x, 1, str-length($y)) { + + $value: set-nth($value, index($value, $x), '-prefix-' + $x); + $expandValue: true; + + } + } + } + + // Expand property? + @if $expandProperty { + @each $vendor in $vendor-prefixes { + #{$vendor}#{$property}: #{str-replace-all($value, '-prefix-', $vendor)}; + } + } + + // Expand just the value? + @elseif $expandValue { + @each $vendor in $vendor-prefixes { + #{$property}: #{str-replace-all($value, '-prefix-', $vendor)}; + } + } + + // Neither? Treat them as a normal declaration. + @else { + #{$property}: #{$value}; + } + + } diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/main.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/main.scss new file mode 100644 index 0000000..acaa0aa --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/main.scss @@ -0,0 +1,58 @@ +@import 'libs/vars'; +@import 'libs/functions'; +@import 'libs/mixins'; +@import 'libs/vendor'; +@import 'libs/breakpoints'; +@import 'libs/html-grid'; +@import 'fontawesome-all.min.css'; + +/* + Hyperspace by HTML5 UP + html5up.net | @ajlkn + Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +*/ + +// Breakpoints. + + @include breakpoints(( + xlarge: ( 1281px, 1680px ), + large: ( 981px, 1280px ), + medium: ( 737px, 980px ), + small: ( 481px, 736px ), + xsmall: ( 361px, 480px ), + xxsmall: ( null, 360px ) + )); + +// Base. + + @import 'base/reset'; + @import 'base/page'; + @import 'base/typography'; + +// Component. + + @import 'components/row'; + @import 'components/box'; + @import 'components/button'; + @import 'components/features'; + @import 'components/form'; + @import 'components/icon'; + @import 'components/image'; + @import 'components/list'; + @import 'components/actions'; + @import 'components/contact'; + @import 'components/icons'; + @import 'components/menu'; + @import 'components/section'; + @import 'components/split'; + @import 'components/spotlights'; + @import 'components/table'; + @import 'components/wrapper'; + +// Layout. + + @import 'layout/header'; + @import 'layout/wrapper'; + @import 'layout/footer'; + @import 'layout/sidebar'; + @import 'layout/intro'; diff --git a/pythoncms/static/themes/front/hyperspace/assets/sass/noscript.scss b/pythoncms/static/themes/front/hyperspace/assets/sass/noscript.scss new file mode 100644 index 0000000..0637c0c --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/assets/sass/noscript.scss @@ -0,0 +1,57 @@ +@import 'libs/vars'; +@import 'libs/functions'; +@import 'libs/mixins'; +@import 'libs/vendor'; +@import 'libs/breakpoints'; +@import 'libs/html-grid'; + +/* + Hyperspace by HTML5 UP + html5up.net | @ajlkn + Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) +*/ + +/* Spotlights */ + + .spotlights { + > section { + > .image { + &:before { + opacity: 0 !important; + } + } + + > .content { + > .inner { + @include vendor('transform', 'none !important'); + opacity: 1 !important; + } + } + } + } + +/* Wrapper */ + + .wrapper { + > .inner { + opacity: 1 !important; + @include vendor('transform', 'none !important'); + } + } + +/* Sidebar */ + + #sidebar { + > .inner { + opacity: 1 !important; + } + + nav { + > ul { + > li { + @include vendor('transform', 'none !important'); + opacity: 1 !important; + } + } + } + } diff --git a/pythoncms/static/themes/front/hyperspace/base.html b/pythoncms/static/themes/front/hyperspace/base.html new file mode 100644 index 0000000..34bfaec --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/base.html @@ -0,0 +1,38 @@ + + + + + Hyperspace by HTML5 UP + + + + + + + {%block body%} + {%endblock%} + + +
+
+ +
+
+ + + + + + + + + + + + diff --git a/pythoncms/static/themes/front/hyperspace/elements.html b/pythoncms/static/themes/front/hyperspace/elements.html new file mode 100644 index 0000000..193db5b --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/elements.html @@ -0,0 +1,363 @@ + + + + + Elements - Hyperspace by HTML5 UP + + + + + + + + + + + +
+ + +
+
+

Elements

+ + +
+

Text

+

This is bold and this is strong. This is italic and this is emphasized. + This is superscript text and this is subscript text. + This is underlined and this is code: for (;;) { ... }. Finally, this is a link.

+
+

Nunc lacinia ante nunc ac lobortis. Interdum adipiscing gravida odio porttitor sem non mi integer non faucibus ornare mi ut ante amet placerat aliquet. Volutpat eu sed ante lacinia sapien lorem accumsan varius montes viverra nibh in adipiscing blandit tempus accumsan.

+
+

Heading Level 2

+

Heading Level 3

+

Heading Level 4

+
+

Blockquote

+
Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan faucibus. Vestibulum ante ipsum primis in faucibus lorem ipsum dolor sit amet nullam adipiscing eu felis.
+

Preformatted

+
i = 0;
+
+while (!deck.isInOrder()) {
+    print 'Iteration ' + i;
+    deck.shuffle();
+    i++;
+}
+
+print 'It took ' + i + ' iterations to sort the deck.';
+
+ + +
+

Lists

+
+
+

Unordered

+
    +
  • Dolor pulvinar etiam.
  • +
  • Sagittis adipiscing.
  • +
  • Felis enim feugiat.
  • +
+

Alternate

+
    +
  • Dolor pulvinar etiam.
  • +
  • Sagittis adipiscing.
  • +
  • Felis enim feugiat.
  • +
+
+
+

Ordered

+
    +
  1. Dolor pulvinar etiam.
  2. +
  3. Etiam vel felis viverra.
  4. +
  5. Felis enim feugiat.
  6. +
  7. Dolor pulvinar etiam.
  8. +
  9. Etiam vel felis lorem.
  10. +
  11. Felis enim et feugiat.
  12. +
+

Icons

+ +
+
+

Actions

+
+
+ + + + +
+
+ + +
+
+
+ + +
+

Table

+

Default

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionPrice
Item OneAnte turpis integer aliquet porttitor.29.99
Item TwoVis ac commodo adipiscing arcu aliquet.19.99
Item Three Morbi faucibus arcu accumsan lorem.29.99
Item FourVitae integer tempus condimentum.19.99
Item FiveAnte turpis integer aliquet porttitor.29.99
100.00
+
+ +

Alternate

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionPrice
Item OneAnte turpis integer aliquet porttitor.29.99
Item TwoVis ac commodo adipiscing arcu aliquet.19.99
Item Three Morbi faucibus arcu accumsan lorem.29.99
Item FourVitae integer tempus condimentum.19.99
Item FiveAnte turpis integer aliquet porttitor.29.99
100.00
+
+
+ + +
+

Buttons

+ + + + + +
    +
  • Disabled
  • +
  • Disabled
  • +
+
+ + +
+

Form

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
    +
  • +
  • +
+
+
+
+
+ + +
+

Image

+

Fit

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Left & Right

+

Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.

+

Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.

+
+ +
+
+ +
+ + +
+
+ +
+
+ + + + + + + + + + + + diff --git a/pythoncms/static/themes/front/hyperspace/generic.html b/pythoncms/static/themes/front/hyperspace/generic.html new file mode 100644 index 0000000..32d1138 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/generic.html @@ -0,0 +1,50 @@ + + + + + Generic - Hyperspace by HTML5 UP + + + + + + + + + + + + + +
+
+ +
+
+ + + + + + + + + + + + diff --git a/pythoncms/static/themes/front/hyperspace/images/pic01.jpg b/pythoncms/static/themes/front/hyperspace/images/pic01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ef01b3f84d1384140db736bb16ed6900aa48c336 GIT binary patch literal 6953 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 KXYTTg|MfpD#K!Uf literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/hyperspace/images/pic02.jpg b/pythoncms/static/themes/front/hyperspace/images/pic02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e78cb6e7102eedb9007255c6796c4bb9b8da8860 GIT binary patch literal 5767 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 F_+PWTPE7y+ literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/hyperspace/images/pic03.jpg b/pythoncms/static/themes/front/hyperspace/images/pic03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e039b33fdadd6f4dc04b2377c01d9d49a166493d GIT binary patch literal 6828 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 Tf$v+_A8Icu+O6TU@h|@a&qt2& literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/hyperspace/images/pic04.jpg b/pythoncms/static/themes/front/hyperspace/images/pic04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..664a4ef8f4036a19a625e6369ba437b555a080db GIT binary patch literal 12171 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 literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/hyperspace/images/pic06.jpg b/pythoncms/static/themes/front/hyperspace/images/pic06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb05dca8312ec1637036ef35469bab192dc9f3ce GIT binary patch literal 2798 zcmbVMO-vit7M?Mg#IebbD?d-OsOn4=2_mo=gKg}T1`iBsXx%z7X^Y;AAI2WXPHc~5 zPYR)`6w;ukMO8OcYN4tE5~!-W0HJh|C<>@-QEAGPoJ1_Tc_Mm{w?Qo0h5Ow*V^UO9 zRlS#s=bU@K^Lx*!lq)|o&&z|E6vLc3bCNML&sJrFv2|WaT)xV%%s#L~3{&~JMonv4 zA?SAJORjiQ?N?k0HRm3T7u=$&$<4fcdaw{rTvjw^zj85?ZxjB1_rBoFB-@0yz2T;C zp+iY$UL7hb(V;hb5<{00fuwNy73a%?!NFW1r)Y8KU@n_41qa&%syv8q!gdQzDxzI( z6GFtQ^PO*x>Xui5_y9`^P+5{u0fq?bY7_+~<^%dZn09ApTMn zjNJXXAtDHGf^QZxC`vrrsV1)El)QGPvrWK_E15|KMXxAHqDPkfAyM{<2)|1Tc)d7X z9scG}OI62SSZ|YG_I8RLp=Q4%0v!mn%B_CU>jkdW+q8o{lP_uUd_t+(&A_gKmHreP z>?kU6O)d7QYPR|UB574qOKG*>?1=iDb#G_#Np+x9Ps*c5+o=>Y?<&czqMCEk{01|7 z*q6mXm&e!a^}_=aw{0A_K}7E+yM^f-~kT*EN1gTv)OXUV#Tr?s;#Xh z=g1M8?Z^?{;c)QBb{4yT|9;Csi~Z0cyTf+a=GeLTs~?pG#%5+7GmmRn8)LGuH8!@g z#GGeXtY`CsVNC3P%G=FlYfSr&6470*tBep zwny9N+oRnhEgaongOuzK2q`SH;ku~Quws8OwPju5yGK{t?f1-2#}fbjyzNAbwdFXj z30Sg2WCWxMh?5{dPEx`=-_1+z_6v3Q%=b)NR_LkKe&VN7H|lTo-l`{iS{moZP2)#r z#z0J3(w2-gZcAMQIq67S(vD1IW_XBOm!8P$FRY03ug69pi)#uu{%+#&2;!O4N%G0HSV;&7 z8$oxArR+byE!)fXN25N@cN{pfzX5|XC&Skf_)RE+=22j$wvKC7;CSiOZ2zyxwba7Q zBF@6hQvGc2ZA;dYl_pHs5yHT}t&_IYD(+`pOR?41!X0ko`L7=O2tx&wK`oAZ6qOT^a^xX&Twr?qA~~^^-Iw@&MEhQ{Ox>C7g+s>9 zMc|{p|5Ihk2%csnw)kG;F1NwYA=>X^Mw&>>^)yj`NEJ~a)9js1A$x!$QD1zQdkcJ$ zfQXT5J>7;5qQ$VMCliucevSwHqs@tPn?xZ;Q>j;Km85eI?+MJ2wGyj6vBi%!C(cu# zX~LEw_VmKgS^$jlRCUt25}mNP>RMd;fPd^8r3r4JHJPGi+LdO#T>1s7_^z;ReKb-& zHJb>gejMU9P-$9xJz=`>IpW?kugMk8U2aptqu_xo06C6G(L%%MF@jnoZ;rku9ZA*d z@fd|cu%A5n{`NZQC4j1}J57zH_4;r|c6F0Wu2otVnEa)%iSD(c+j~i~qMs#nJL!0R z+frl1JbmN%MRJxX^w{AqPoZ^nC`JKbRgnJ6q0Qk6TAR?^ro2w7vi8A=pFVsIW9kBF zUHgMkV<@p2X=yYyPIWS2@L?uRZE+BPx;Xaa`{{L_j0@8`KkZ0c>G*-e#AzH$M%EoC zLN{E)LucXK3oD+rR*g(HG8tKIYMD$xGe#mAi^gQd$XRKqy5#PLplPf2{u}=Qp4y8b z0upBoxkZ{V6mj5zC5>x@r%Q1dfX6=l*U24I^n-+Hge8zbpq;RYH^xtm_kW-LJM=!c z#jo^E^S9u*VGV)8EI4CEp6QPa&OrMQf%6C0nrmYbEay8`wtYC%XXnm_u=?ui>RMl{ GJp2tLBG0M- literal 0 HcmV?d00001 diff --git a/pythoncms/static/themes/front/hyperspace/index.html b/pythoncms/static/themes/front/hyperspace/index.html new file mode 100644 index 0000000..803382a --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/index.html @@ -0,0 +1,177 @@ +{%extends 'hyperspace/base.html'%} + + +{%block body%} + + + + +
+ + +
+
+

Hyperspace

+

Just another fine responsive site template designed by HTML5 UP
+ and released for free under the Creative Commons.

+ +
+
+ + +
+
+ +
+
+

Sed ipsum dolor

+

Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.

+ +
+
+
+
+ +
+
+

Feugiat consequat

+

Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.

+ +
+
+
+
+ +
+
+

Ultricies aliquam

+

Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.

+ +
+
+
+
+ + +
+
+

What we do

+

Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.

+
+
+ +

Lorem ipsum amet

+

Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.

+
+
+ +

Aliquam sed nullam

+

Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.

+
+
+ +

Sed erat ullam corper

+

Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.

+
+
+ +

Veroeros quis lorem

+

Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.

+
+
+ +

Urna quis bibendum

+

Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.

+
+
+ +

Aliquam urna dapibus

+

Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.

+
+
+ +
+
+ + +
+
+

Get in touch

+

Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.

+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+
+
+
+ +
+{%endblock%} diff --git a/pythoncms/static/themes/front/hyperspace/info.json b/pythoncms/static/themes/front/hyperspace/info.json new file mode 100644 index 0000000..e00ba90 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/info.json @@ -0,0 +1,4 @@ +{ + "author": "ARJ", + "version": "1.0.20000000000003" +} diff --git a/pythoncms/static/themes/front/hyperspace/page.html b/pythoncms/static/themes/front/hyperspace/page.html new file mode 100644 index 0000000..be94c71 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/page.html @@ -0,0 +1,17 @@ +{%extends 'hyperspace/base.html'%} +{%block body%} + + +
+ + +
+
+

{{page.title}}

+ + {{page.get_content()}} +
+
+ +
+{%endblock%} diff --git a/pythoncms/static/themes/front/hyperspace/render_demo.html b/pythoncms/static/themes/front/hyperspace/render_demo.html new file mode 100644 index 0000000..b42ae9b --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/render_demo.html @@ -0,0 +1,3 @@ + +

WWW Index

+

Fruit {{ fruit }}

diff --git a/pythoncms/static/themes/front/hyperspace/sections/footer.html b/pythoncms/static/themes/front/hyperspace/sections/footer.html new file mode 100644 index 0000000..e69de29 diff --git a/pythoncms/static/themes/front/hyperspace/sections/nav.html b/pythoncms/static/themes/front/hyperspace/sections/nav.html new file mode 100644 index 0000000..e69de29 diff --git a/pythoncms/static/themes/front/hyperspace/sections/resources.html b/pythoncms/static/themes/front/hyperspace/sections/resources.html new file mode 100644 index 0000000..e69de29 diff --git a/pythoncms/static/themes/front/hyperspace/styles.css b/pythoncms/static/themes/front/hyperspace/styles.css new file mode 100644 index 0000000..3f9cc33 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/styles.css @@ -0,0 +1,41 @@ + + html { + scroll-behavior: smooth; + } + .suggest { + + } + + .suggest span { + padding-left: 5px; + padding-right: 5px; + margin: 5px; + min-width: 50px; + } + + a{ + text-decoration: inherit; + color: inherit; + } + a:hover{ + text-decoration: inherit; + color: inherit; + } + + #flashed-messages{ + padding: 5px; + position: fixed; + right: 5px; + top: 5px; + z-index: 10; + height: 300px; + overflow-y: scroll; + + } + #flashed-messages::-webkit-scrollbar { + display: none; + } + /* Hide scrollbar for IE and Edge */ + #flashed-messages{ + -ms-overflow-style: none; + } From 2c0e94b976ea5fa37d3fca4af65eca83f031c07a Mon Sep 17 00:00:00 2001 From: Abdur-Rahmaan Janhangeer Date: Tue, 31 Jan 2023 23:59:03 +0400 Subject: [PATCH 3/4] feat: Refine themes --- pythoncms/modules/box__default/page/global.py | 4 + .../modules/box__default/page/helpers.py | 7 + pythoncms/modules/contact/view.py | 7 +- .../static/themes/front/blogus/index.html | 409 ------------------ .../static/themes/front/blogus/info.json | 4 - .../static/themes/front/blogus/page.html | 15 - .../themes/front/blogus/render_demo.html | 3 - .../themes/front/blogus/sections/footer.html | 0 .../themes/front/blogus/sections/nav.html | 0 .../front/blogus/sections/resources.html | 0 .../static/themes/front/blogus/styles.css | 41 -- .../themes/front/editorial/contact.html | 46 ++ .../static/themes/front/editorial/index.html | 50 +-- .../front/editorial/sections/sidebar.html | 8 +- .../themes/front/hyperspace/contact.html | 46 ++ .../static/themes/front/hyperspace/index.html | 26 +- 16 files changed, 121 insertions(+), 545 deletions(-) create mode 100644 pythoncms/modules/box__default/page/global.py create mode 100644 pythoncms/modules/box__default/page/helpers.py delete mode 100644 pythoncms/static/themes/front/blogus/index.html delete mode 100644 pythoncms/static/themes/front/blogus/info.json delete mode 100644 pythoncms/static/themes/front/blogus/page.html delete mode 100644 pythoncms/static/themes/front/blogus/render_demo.html delete mode 100644 pythoncms/static/themes/front/blogus/sections/footer.html delete mode 100644 pythoncms/static/themes/front/blogus/sections/nav.html delete mode 100644 pythoncms/static/themes/front/blogus/sections/resources.html delete mode 100644 pythoncms/static/themes/front/blogus/styles.css create mode 100644 pythoncms/static/themes/front/editorial/contact.html create mode 100644 pythoncms/static/themes/front/hyperspace/contact.html diff --git a/pythoncms/modules/box__default/page/global.py b/pythoncms/modules/box__default/page/global.py new file mode 100644 index 0000000..dc7bb94 --- /dev/null +++ b/pythoncms/modules/box__default/page/global.py @@ -0,0 +1,4 @@ +from .helpers import * + + +available_everywhere = {"get_pages": get_pages} diff --git a/pythoncms/modules/box__default/page/helpers.py b/pythoncms/modules/box__default/page/helpers.py new file mode 100644 index 0000000..395de66 --- /dev/null +++ b/pythoncms/modules/box__default/page/helpers.py @@ -0,0 +1,7 @@ +from init import db + +from .models import Page + + +def get_pages(): + return db.session.query(Page).all() diff --git a/pythoncms/modules/contact/view.py b/pythoncms/modules/contact/view.py index 978aa47..3f50a80 100644 --- a/pythoncms/modules/contact/view.py +++ b/pythoncms/modules/contact/view.py @@ -5,6 +5,7 @@ from flask import request from flask import url_for from flask_login import login_required +from modules.box__default.theme.helpers import get_active_front_theme from shopyo.api.html import notify_success from .forms import ContactForm @@ -24,7 +25,7 @@ def index(): form = ContactForm() context.update({"form": form}) - return render_template("contact/contact_form.html", **context) + return render_template(f"{get_active_front_theme()}/contact.html", **context) @contact_blueprint.route("/validate_message", methods=["GET", "POST"]) @@ -53,6 +54,8 @@ def dashboard(page): context = {} per_page = 10 - messages = ContactMessage.query.paginate(page, per_page, error_out=False) + messages = ContactMessage.query.paginate( + page=page, per_page=per_page, error_out=False + ) context.update({"messages": messages}) return render_template("contact/dashboard.html", **context) diff --git a/pythoncms/static/themes/front/blogus/index.html b/pythoncms/static/themes/front/blogus/index.html deleted file mode 100644 index 812efcd..0000000 --- a/pythoncms/static/themes/front/blogus/index.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - - Bootstrap demo - - - - - - - -
-
-
-

Title of a longer featured blog post

-

Multiple lines of text that form the lede, informing new readers quickly and - efficiently about what’s most interesting in this post’s contents.

-

Continue reading...

-
-
- -
-
-
-
- World -

Featured post

-
Nov 12
-

This is a wider card with supporting text below as a natural - lead-in to additional content.

- Continue reading -
-
- -
-
-
-
-
-
- Design -

Post title

-
Nov 11
-

This is a wider card with supporting text below as a natural lead-in to - additional content.

- Continue reading -
-
- -
-
-
-
- -
-
-

- From the Firehose -

- -
-

Sample blog post

- - -

This blog post shows a few different types of content that’s supported and styled with Bootstrap. - Basic typography, lists, tables, images, code, and more are all supported as expected.

-
-

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-

Blockquotes

-

This is an example blockquote in action:

-
-

Quoted text goes here.

-
-

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-

Example lists

-

This is some additional paragraph placeholder content. It's a slightly shorter version of the - other highly repetitive body text used throughout. This is an example unordered list:

-
    -
  • First list item
  • -
  • Second list item with a longer description
  • -
  • Third list item to close it out
  • -
-

And this is an ordered list:

-
    -
  1. First list item
  2. -
  3. Second list item with a longer description
  4. -
  5. Third list item to close it out
  6. -
-

And this is a definition list:

-
-
HyperText Markup Language (HTML)
-
The language used to describe and define the content of a Web page
-
Cascading Style Sheets (CSS)
-
Used to describe the appearance of Web content
-
JavaScript (JS)
-
The programming language used to build advanced Web sites and applications
-
-

Inline HTML elements

-

HTML defines a long list of available inline tags, a complete list of which can be found on the - Mozilla Developer - Network.

-
    -
  • To bold text, use <strong>.
  • -
  • To italicize text, use <em>.
  • -
  • Abbreviations, like HTML should use <abbr>, with an optional title attribute for the full phrase. -
  • -
  • Citations, like β€” Mark Otto, should use <cite>.
  • -
  • Deleted text should use <del> and inserted - text should use <ins>.
  • -
  • Superscript text uses <sup> and subscript - text uses <sub>. -
  • -
-

Most of these elements are styled by browsers with few modifications on our part.

-

Heading

-

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-

Sub-heading

-

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-
Example code block
-

This is some additional paragraph placeholder content. It's a slightly shorter version of the - other highly repetitive body text used throughout.

-
- -
-

Another blog post

- - -

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-
-

Longer quote goes here, maybe with some emphasized text in the middle of it. -

-
-

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-

Example table

-

And don't forget about tables in these posts:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameUpvotesDownvotes
Alice1011
Bob43
Charlie79
Totals2123
- -

This is some additional paragraph placeholder content. It's a slightly shorter version of the - other highly repetitive body text used throughout.

-
- -
-

New feature

- - -

This is some additional paragraph placeholder content. It has been written to fill the available - space and show how a longer snippet of text affects the surrounding content. We'll repeat it - often to keep the demonstration flowing, so be on the lookout for this exact same string of - text.

-
    -
  • First list item
  • -
  • Second list item with a longer description
  • -
  • Third list item to close it out
  • -
-

This is some additional paragraph placeholder content. It's a slightly shorter version of the - other highly repetitive body text used throughout.

-
- - - -
- -
-
-
-

About

-

Customize this section to tell your visitors a little bit about your - publication, writers, content, or something else entirely. Totally up to you.

-
- - - -
-

Elsewhere

-
    -
  1. GitHub
  2. -
  3. Twitter
  4. -
  5. Facebook
  6. -
-
-
-
-
- -
- - - - - - diff --git a/pythoncms/static/themes/front/blogus/info.json b/pythoncms/static/themes/front/blogus/info.json deleted file mode 100644 index e00ba90..0000000 --- a/pythoncms/static/themes/front/blogus/info.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "author": "ARJ", - "version": "1.0.20000000000003" -} diff --git a/pythoncms/static/themes/front/blogus/page.html b/pythoncms/static/themes/front/blogus/page.html deleted file mode 100644 index 129bdaf..0000000 --- a/pythoncms/static/themes/front/blogus/page.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - {{ page.title }} - - - Demo content page, need to add set lang mechanism by calling `/i18n/set-lang?lang=fr`. -

- {{ page.title }} -

- {{ page.get_content() }} - - diff --git a/pythoncms/static/themes/front/blogus/render_demo.html b/pythoncms/static/themes/front/blogus/render_demo.html deleted file mode 100644 index b42ae9b..0000000 --- a/pythoncms/static/themes/front/blogus/render_demo.html +++ /dev/null @@ -1,3 +0,0 @@ - -

WWW Index

-

Fruit {{ fruit }}

diff --git a/pythoncms/static/themes/front/blogus/sections/footer.html b/pythoncms/static/themes/front/blogus/sections/footer.html deleted file mode 100644 index e69de29..0000000 diff --git a/pythoncms/static/themes/front/blogus/sections/nav.html b/pythoncms/static/themes/front/blogus/sections/nav.html deleted file mode 100644 index e69de29..0000000 diff --git a/pythoncms/static/themes/front/blogus/sections/resources.html b/pythoncms/static/themes/front/blogus/sections/resources.html deleted file mode 100644 index e69de29..0000000 diff --git a/pythoncms/static/themes/front/blogus/styles.css b/pythoncms/static/themes/front/blogus/styles.css deleted file mode 100644 index 3f9cc33..0000000 --- a/pythoncms/static/themes/front/blogus/styles.css +++ /dev/null @@ -1,41 +0,0 @@ - - html { - scroll-behavior: smooth; - } - .suggest { - - } - - .suggest span { - padding-left: 5px; - padding-right: 5px; - margin: 5px; - min-width: 50px; - } - - a{ - text-decoration: inherit; - color: inherit; - } - a:hover{ - text-decoration: inherit; - color: inherit; - } - - #flashed-messages{ - padding: 5px; - position: fixed; - right: 5px; - top: 5px; - z-index: 10; - height: 300px; - overflow-y: scroll; - - } - #flashed-messages::-webkit-scrollbar { - display: none; - } - /* Hide scrollbar for IE and Edge */ - #flashed-messages{ - -ms-overflow-style: none; - } diff --git a/pythoncms/static/themes/front/editorial/contact.html b/pythoncms/static/themes/front/editorial/contact.html new file mode 100644 index 0000000..ad1bf60 --- /dev/null +++ b/pythoncms/static/themes/front/editorial/contact.html @@ -0,0 +1,46 @@ +{%extends 'editorial/base.html'%} + + +{%block body%} + + +
+ + +
+
+ +
+

Form

+
+
+
+ {{form.name.label}} + {{ form.name }} +
+
+ {{form.email.label}} + {{ form.email }} +
+ +
+ {{form.message.label}} + {{ form.message }} +
+
+
    +
  • + +
+
+
+
+
+
+
+ + {%include 'editorial/sections/sidebar.html'%} +
+ + +{%endblock%} diff --git a/pythoncms/static/themes/front/editorial/index.html b/pythoncms/static/themes/front/editorial/index.html index bd9aa22..94b334f 100644 --- a/pythoncms/static/themes/front/editorial/index.html +++ b/pythoncms/static/themes/front/editorial/index.html @@ -80,57 +80,19 @@

Sed magna finibus

-

Ipsum sed dolor

+

Posts

+ {%for page in get_pages()%}
-

Interdum aenean

+

{{page.title}}

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

-
-
- -

Nulla amet dolore

-

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

- -
-
- -

Tempus ullamcorper

-

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

- -
-
- -

Sed etiam facilis

-

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

- -
-
- -

Feugiat lorem aenean

-

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

- -
-
- -

Amet varius aliquam

-

Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.

-
+ {%endfor%}
@@ -141,4 +103,4 @@

Amet varius aliquam

-{%endblock%} +{%endblock%} diff --git a/pythoncms/static/themes/front/editorial/sections/sidebar.html b/pythoncms/static/themes/front/editorial/sections/sidebar.html index aa66b58..6e28984 100644 --- a/pythoncms/static/themes/front/editorial/sections/sidebar.html +++ b/pythoncms/static/themes/front/editorial/sections/sidebar.html @@ -15,9 +15,9 @@

Menu

diff --git a/pythoncms/static/themes/front/hyperspace/contact.html b/pythoncms/static/themes/front/hyperspace/contact.html new file mode 100644 index 0000000..f2a3d75 --- /dev/null +++ b/pythoncms/static/themes/front/hyperspace/contact.html @@ -0,0 +1,46 @@ +{%extends 'hyperspace/base.html'%} + + +{%block body%} + + +
+ + +
+
+ +
+

Form

+
+
+
+ {{form.name.label}} + {{ form.name }} +
+
+ {{form.email.label}} + {{ form.email }} +
+ +
+ {{form.message.label}} + {{ form.message }} +
+
+
    +
  • + +
+
+
+
+
+
+
+ +
+ + + +{%endblock%} diff --git a/pythoncms/static/themes/front/hyperspace/index.html b/pythoncms/static/themes/front/hyperspace/index.html index 803382a..3247ab2 100644 --- a/pythoncms/static/themes/front/hyperspace/index.html +++ b/pythoncms/static/themes/front/hyperspace/index.html @@ -10,7 +10,7 @@
  • Welcome
  • Who we are
  • What we do
  • -
  • Get in touch
  • +
  • Get in touch
  • @@ -120,27 +120,7 @@

    Aliquam urna dapibus

    Get in touch

    Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.

    -
    -
    -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - -
    -
    +
    • @@ -174,4 +154,4 @@

      Social

    -{%endblock%} +{%endblock%} From 6af792aed9bb4a3a1571e5c87be3355da17b8d1f Mon Sep 17 00:00:00 2001 From: Abdur-Rahmaan Janhangeer Date: Wed, 1 Feb 2023 00:08:11 +0400 Subject: [PATCH 4/4] chore: prepare deploy --- README.md | 24 ++++++++++++++++++++++++ requirements.txt | 1 + setup.py | 15 ++++++++------- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d9fbe4f..ce5fd92 100644 --- a/README.md +++ b/README.md @@ -1 +1,25 @@ # Welcome to pythoncms + + +Local dev + +Install package + + +``` +python -m pip install -e . +``` +Then initialise + +``` +cd pythoncms +shopyo initialise +flask --debug run +``` + +for migrating + +``` +flask db migrate +flask db upgrade +``` diff --git a/requirements.txt b/requirements.txt index 0fabe83..32d5f16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ shopyo==4.8.6 +SQLAlchemy==1.4.46 diff --git a/setup.py b/setup.py index 826f901..5bd5d19 100644 --- a/setup.py +++ b/setup.py @@ -34,8 +34,8 @@ long_description=long_description, # Optional long_description_content_type="text/markdown", # Optional (see note above) url="", # Optional - author="", # Optional - author_email="", # Optional + author="Abdur-Rahmaan Janhangeer", # Optional + author_email="arj.python@gmail.com", # Optional # Classifiers help users find your project by categorizing it. # # For a list of valid classifiers, see https://pypi.org/classifiers/ @@ -54,12 +54,13 @@ # that you indicate whether you support Python 2, Python 3 or both. # These classifiers are *not* checked by 'pip install'. See instead # 'python_requires' below. - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ], - keywords="", # Optional + keywords="cms", # Optional # You can just specify package directories manually here if your project is # simple. Or you can use find_packages(). # @@ -72,13 +73,13 @@ # packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required packages=["pythoncms"], include_package_data=True, - python_requires=">=3.6", + python_requires=">=3.7", install_requires=open(os.path.join(here, "requirements.txt"), encoding="utf-8") .read() .split("\n"), # Optional project_urls={ # Optional - "Bug Reports": "", - "Source": "", + "Bug Reports": "https://github.com/shopyo/pythoncms/issues", + "Source": "https://github.com/shopyo/pythoncms", }, entry_points={"console_scripts": ["pythoncms=pythoncms.cli:cli"]}, )