mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-10 09:06:21 +01:00
BS5 Theme
This commit is contained in:
0
allianceauth/theme/__init__.py
Normal file
0
allianceauth/theme/__init__.py
Normal file
9
allianceauth/theme/apps.py
Normal file
9
allianceauth/theme/apps.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme"
|
||||
label = "theme"
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
0
allianceauth/theme/bootstrap/__init__.py
Normal file
0
allianceauth/theme/bootstrap/__init__.py
Normal file
11
allianceauth/theme/bootstrap/apps.py
Normal file
11
allianceauth/theme/bootstrap/apps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BootstrapThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.bootstrap"
|
||||
label = "bootstrap"
|
||||
version = "5.3.0"
|
||||
verbose_name = f"Bootstrap v{version}"
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
33
allianceauth/theme/bootstrap/auth_hooks.py
Normal file
33
allianceauth/theme/bootstrap/auth_hooks.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from allianceauth import hooks
|
||||
from allianceauth.theme.hooks import ThemeHook
|
||||
|
||||
|
||||
class BootstrapThemeHook(ThemeHook):
|
||||
"""
|
||||
Bootstrap in all its glory!
|
||||
https://getbootstrap.com/
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ThemeHook.__init__(
|
||||
self,
|
||||
"Bootstrap",
|
||||
"Powerful, extensible, and feature-packed frontend toolkit.",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css",
|
||||
"integrity": "sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.min.js",
|
||||
"integrity": "sha512-3dZ9wIrMMij8rOH7X3kLfXAzwtcHpuYpEgQg1OA4QAob1e81H8ntUQmQm3pBudqIoySO5j0tHN4ENzA6+n2r4w=="
|
||||
}],
|
||||
header_padding="3.5em"
|
||||
)
|
||||
|
||||
|
||||
@hooks.register('theme_hook')
|
||||
def register_darkly_hook():
|
||||
return BootstrapThemeHook()
|
||||
0
allianceauth/theme/bootstrap_dark/__init__.py
Normal file
0
allianceauth/theme/bootstrap_dark/__init__.py
Normal file
11
allianceauth/theme/bootstrap_dark/apps.py
Normal file
11
allianceauth/theme/bootstrap_dark/apps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BootstrapDarkThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.bootstrap_dark"
|
||||
label = "bootstrap_dark"
|
||||
version = "5.3.0"
|
||||
verbose_name = f"Bootstrap Dark v{version}"
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
34
allianceauth/theme/bootstrap_dark/auth_hooks.py
Normal file
34
allianceauth/theme/bootstrap_dark/auth_hooks.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from allianceauth import hooks
|
||||
from allianceauth.theme.hooks import ThemeHook
|
||||
|
||||
|
||||
class BootstrapDarkThemeHook(ThemeHook):
|
||||
"""
|
||||
Bootstrap in all its glory!
|
||||
https://getbootstrap.com/
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ThemeHook.__init__(
|
||||
self,
|
||||
"Bootstrap Dark",
|
||||
"Powerful, extensible, and feature-packed frontend toolkit.",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css",
|
||||
"integrity": "sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.min.js",
|
||||
"integrity": "sha512-3dZ9wIrMMij8rOH7X3kLfXAzwtcHpuYpEgQg1OA4QAob1e81H8ntUQmQm3pBudqIoySO5j0tHN4ENzA6+n2r4w=="
|
||||
}],
|
||||
html_tags="data-bs-theme=dark",
|
||||
header_padding="3.5em"
|
||||
)
|
||||
|
||||
|
||||
@hooks.register('theme_hook')
|
||||
def register_bootstrap_dark_hook():
|
||||
return BootstrapDarkThemeHook()
|
||||
0
allianceauth/theme/darkly/__init__.py
Normal file
0
allianceauth/theme/darkly/__init__.py
Normal file
11
allianceauth/theme/darkly/apps.py
Normal file
11
allianceauth/theme/darkly/apps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class DarklyThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.darkly"
|
||||
label = "darkly"
|
||||
version = "5.3.0"
|
||||
verbose_name = f"Bootswatch Darkly v{version}"
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
33
allianceauth/theme/darkly/auth_hooks.py
Normal file
33
allianceauth/theme/darkly/auth_hooks.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from allianceauth import hooks
|
||||
from allianceauth.theme.hooks import ThemeHook
|
||||
|
||||
|
||||
class DarklyThemeHook(ThemeHook):
|
||||
"""
|
||||
The default auth theme
|
||||
https://bootswatch.com/darkly/
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ThemeHook.__init__(
|
||||
self,
|
||||
"Darkly",
|
||||
"Flatly in night mode!",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.0/darkly/bootstrap.min.css",
|
||||
"integrity": "sha512-3xynESL0QF3ERUl9se1VJk043nWT+UzWJveifBw7kLtC226vyGINZFtmyK015F83KBSNW+67alYSY2cCj1LHOQ=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.min.js",
|
||||
"integrity": "sha512-3dZ9wIrMMij8rOH7X3kLfXAzwtcHpuYpEgQg1OA4QAob1e81H8ntUQmQm3pBudqIoySO5j0tHN4ENzA6+n2r4w=="
|
||||
}],
|
||||
header_padding="4.5em"
|
||||
)
|
||||
|
||||
|
||||
@hooks.register('theme_hook')
|
||||
def register_darkly_hook():
|
||||
return DarklyThemeHook()
|
||||
0
allianceauth/theme/flatly/__init__.py
Normal file
0
allianceauth/theme/flatly/__init__.py
Normal file
11
allianceauth/theme/flatly/apps.py
Normal file
11
allianceauth/theme/flatly/apps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FlatlyThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.flatly"
|
||||
label = "flatly"
|
||||
version = "5.3.0"
|
||||
verbose_name = f"Bootswatch Flatly v{version}"
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
33
allianceauth/theme/flatly/auth_hooks.py
Normal file
33
allianceauth/theme/flatly/auth_hooks.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from allianceauth import hooks
|
||||
from allianceauth.theme.hooks import ThemeHook
|
||||
|
||||
|
||||
class FlatlyThemeHook(ThemeHook):
|
||||
"""
|
||||
auth light theme
|
||||
https://bootswatch.com/flatly/
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ThemeHook.__init__(
|
||||
self,
|
||||
"Flatly",
|
||||
"Flat and modern!",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.0/flatly/bootstrap.min.css",
|
||||
"integrity": "sha512-N/JRw8RFoUkWgQIpunoKtmZShzrHbs724xV4DMh+LSNjebmrgNy2dzAIUhoOqSazEZ/bLlulWy2muCxletfrsA=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.min.js",
|
||||
"integrity": "sha512-3dZ9wIrMMij8rOH7X3kLfXAzwtcHpuYpEgQg1OA4QAob1e81H8ntUQmQm3pBudqIoySO5j0tHN4ENzA6+n2r4w=="
|
||||
}],
|
||||
header_padding="4.5em"
|
||||
)
|
||||
|
||||
|
||||
@hooks.register('theme_hook')
|
||||
def register_flatly_hook():
|
||||
return FlatlyThemeHook()
|
||||
47
allianceauth/theme/hooks.py
Normal file
47
allianceauth/theme/hooks.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class ThemeHook:
|
||||
"""
|
||||
Theme hook for injecting a Bootstrap 5 Theme and associated JS into alliance auth.
|
||||
these can be local or CDN delivered
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str,
|
||||
description: str,
|
||||
css: List[dict],
|
||||
js: List[dict],
|
||||
css_template: Optional[str] = None,
|
||||
js_template: Optional[str] = None,
|
||||
html_tags: Optional[str] = "",
|
||||
header_padding: Optional[str] = "4em"):
|
||||
"""
|
||||
:param name: Theme python name
|
||||
:type name: str
|
||||
:param description: Theme verbose name
|
||||
:type description: str
|
||||
:param css: CSS paths to load
|
||||
:type css: List[dict]
|
||||
:param js: JS paths to load
|
||||
:type js: List[dict]
|
||||
:param css_template: _description_, defaults to None
|
||||
:type css_template: Optional[str], optional
|
||||
:param js_template: _description_, defaults to None
|
||||
:type js_template: Optional[str], optional
|
||||
"""
|
||||
self.name = name
|
||||
self.description = description
|
||||
|
||||
# Direct from CDN
|
||||
self.css = css
|
||||
self.js = js
|
||||
|
||||
# Load a django template with static file definitions
|
||||
self.css_template = css_template
|
||||
self.js_template = js_template
|
||||
|
||||
self.html_tags = html_tags
|
||||
self.header_padding = header_padding
|
||||
def get_name(self):
|
||||
return f"{self.__class__.__module__}.{self.__class__.__name__}"
|
||||
0
allianceauth/theme/materia/__init__.py
Normal file
0
allianceauth/theme/materia/__init__.py
Normal file
11
allianceauth/theme/materia/apps.py
Normal file
11
allianceauth/theme/materia/apps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MateriaThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.materia"
|
||||
label = "materia"
|
||||
version = "5.3.0"
|
||||
verbose_name = f"Bootswatch Materia v{version}"
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
33
allianceauth/theme/materia/auth_hooks.py
Normal file
33
allianceauth/theme/materia/auth_hooks.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from allianceauth import hooks
|
||||
from allianceauth.theme.hooks import ThemeHook
|
||||
|
||||
|
||||
class MateriaThemeHook(ThemeHook):
|
||||
"""
|
||||
Materia theme
|
||||
https://bootswatch.com/materia/
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ThemeHook.__init__(
|
||||
self,
|
||||
"Materia",
|
||||
"Material is the metaphor",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.0/materia/bootstrap.min.css",
|
||||
"integrity": "sha512-FukZyva60KXjmN0uleimuMCoAUwuRha1fSCdzWtxZ29YBIev3gGBU0FpTIEfmGZ9YSrmgW4Pv5geC/q11RuATg=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.min.js",
|
||||
"integrity": "sha512-3dZ9wIrMMij8rOH7X3kLfXAzwtcHpuYpEgQg1OA4QAob1e81H8ntUQmQm3pBudqIoySO5j0tHN4ENzA6+n2r4w=="
|
||||
}],
|
||||
header_padding="5.25em"
|
||||
)
|
||||
|
||||
|
||||
@hooks.register('theme_hook')
|
||||
def register_materia_hook():
|
||||
return MateriaThemeHook()
|
||||
0
allianceauth/theme/templates/__init__.py
Normal file
0
allianceauth/theme/templates/__init__.py
Normal file
0
allianceauth/theme/templates/theme/__init__.py
Normal file
0
allianceauth/theme/templates/theme/__init__.py
Normal file
10
allianceauth/theme/templates/theme/theme_imports_css.html
Normal file
10
allianceauth/theme/templates/theme/theme_imports_css.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% load static %}
|
||||
<!-- allianceauth.theme.{{ theme.name }} CSS -->
|
||||
{% if theme.css_template %}
|
||||
{% include theme.css_template %}
|
||||
{% else %}
|
||||
{% for x in theme.css %}
|
||||
<link rel="stylesheet" href="{{ x.url }}" integrity="{{ x.integrity }}" crossorigin="anonymous" referrerpolicy="no-referrer"/>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<!-- allianceauth.theme.{{ theme.name }} CSS Ends -->
|
||||
10
allianceauth/theme/templates/theme/theme_imports_js.html
Normal file
10
allianceauth/theme/templates/theme/theme_imports_js.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% load static %}
|
||||
<!-- allianceauth.theme.{{ theme.name }} JS -->
|
||||
{% if theme.js_template %}
|
||||
{% include theme.css_template %}
|
||||
{% else %}
|
||||
{% for x in theme.js %}
|
||||
<script src="{{ x.url }}" integrity="{{ x.integrity }}" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<!-- allianceauth.theme.{{ theme.name }} JS Ends-->
|
||||
9
allianceauth/theme/templates/theme/theme_select.html
Normal file
9
allianceauth/theme/templates/theme/theme_select.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<form action="{% url 'theme' %}?next={{ next|urlencode }}" method="post">
|
||||
{% csrf_token %}
|
||||
<select name="theme" value="theme" class="form-select" aria-label="" onchange="this.form.submit()">
|
||||
<option selected>Select Theme</option>
|
||||
{% for theme in themes %}
|
||||
<option value="{{ theme.get_name }}">{{ theme.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
0
allianceauth/theme/templatetags/__init__.py
Normal file
0
allianceauth/theme/templatetags/__init__.py
Normal file
73
allianceauth/theme/templatetags/theme_tags.py
Normal file
73
allianceauth/theme/templatetags/theme_tags.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
|
||||
from allianceauth.hooks import get_hooks
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
def hook_to_name(th):
|
||||
return f"{th.__class__.__module__}.{th.__class__.__name__}"
|
||||
|
||||
|
||||
def get_theme_from_hooks(theme, hooks):
|
||||
for h in hooks:
|
||||
_h = h()
|
||||
_hn = hook_to_name(_h)
|
||||
if _hn == theme:
|
||||
return _h
|
||||
|
||||
|
||||
def get_theme(request):
|
||||
theme = settings.DEFAULT_THEME
|
||||
hooks = get_hooks('theme_hook')
|
||||
if request.user:
|
||||
theme = request.user.profile.theme or theme
|
||||
|
||||
theme_hook = get_theme_from_hooks(theme, hooks)
|
||||
|
||||
if not theme_hook:
|
||||
theme_hook = get_theme_from_hooks(settings.DEFAULT_THEME, hooks)
|
||||
|
||||
return theme_hook
|
||||
|
||||
|
||||
def get_theme_context(request):
|
||||
return {
|
||||
'theme': get_theme(request)
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag('theme/theme_imports_css.html', takes_context=True)
|
||||
def theme_css(context):
|
||||
request = context['request']
|
||||
return get_theme_context(request)
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def theme_html_tags(context):
|
||||
request = context['request']
|
||||
theme = get_theme(request)
|
||||
return getattr(theme, "html_tags", "")
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def header_padding_size(context):
|
||||
request = context['request']
|
||||
theme = get_theme(request)
|
||||
return getattr(theme, "header_padding")
|
||||
|
||||
|
||||
@register.inclusion_tag('theme/theme_imports_js.html', takes_context=True)
|
||||
def theme_js(context):
|
||||
request = context['request']
|
||||
return get_theme_context(request)
|
||||
|
||||
|
||||
@register.inclusion_tag('theme/theme_select.html', takes_context=True)
|
||||
def theme_select(context):
|
||||
request = context['request']
|
||||
return {
|
||||
'next': request.path,
|
||||
'themes': get_hooks('theme_hook')
|
||||
}
|
||||
Reference in New Issue
Block a user