mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-22 03:13:12 +00:00
Add custom themes
This commit is contained in:
parent
3a9a839148
commit
0f40663fac
27 changed files with 289 additions and 0 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -47,3 +47,7 @@ settings_local.py
|
||||||
local_routers.py
|
local_routers.py
|
||||||
re2o.png
|
re2o.png
|
||||||
media/
|
media/
|
||||||
|
|
||||||
|
# themes
|
||||||
|
static/css/themes/*
|
||||||
|
!static/css/themes/default.css
|
0
static/css/themes/default.css
Normal file
0
static/css/themes/default.css
Normal file
|
@ -56,6 +56,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
<link href="{% static 'css/typeaheadjs.css' %}" rel="stylesheet">
|
<link href="{% static 'css/typeaheadjs.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/bootstrap-tokenfield.css' %}" rel="stylesheet">
|
<link href="{% static 'css/bootstrap-tokenfield.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet">
|
||||||
|
{# load theme #}
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<link href="{% static 'css/themes/' %}{{request.user.theme}}" rel="stylesheet">
|
||||||
|
{% else %}
|
||||||
|
<link href="{% static 'css/themes/default.css' %}" rel="stylesheet">
|
||||||
|
{% endif %}
|
||||||
<link href="{% static 'css/base.css' %}" rel="stylesheet">
|
<link href="{% static 'css/base.css' %}" rel="stylesheet">
|
||||||
|
|
||||||
{# Favicon with iOS, Android, touchbar support #}
|
{# Favicon with iOS, Android, touchbar support #}
|
||||||
|
|
23
themes/README.md
Normal file
23
themes/README.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Custom themes for Re2o
|
||||||
|
|
||||||
|
The following themes are licensed under MIT to Thomas Park. See https://bootswatch.com.
|
||||||
|
|
||||||
|
By default, only the default.css is enabled, which is a blank css file.
|
||||||
|
|
||||||
|
**How to activate new themes ?**
|
||||||
|
|
||||||
|
You can activate themes by copying them, or making a symbolic link to the `static/css/themes` directory and collecting the statics.
|
||||||
|
|
||||||
|
**How to change the default theme ?**
|
||||||
|
|
||||||
|
You can change the default theme by changing the default.css file.
|
||||||
|
|
||||||
|
**How to add new theme ?**
|
||||||
|
|
||||||
|
You can add a brand new theme by adding a css file to the `static/css/themes` directory and collecting the statics.
|
||||||
|
|
||||||
|
**What happens if I delete a theme ?**
|
||||||
|
|
||||||
|
User with this theme will continue to try to load this theme, without success if the theme was correctly deleted. It won't cause any malfunctions on the client side, and the default re2o theme (but not the default.css) theme will be loaded. Users will not be able to select this theme anymore afterwards.
|
||||||
|
|
||||||
|
Try to not delete the default.css theme.
|
11
themes/cerulan.css
Normal file
11
themes/cerulan.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/cosmo.css
Normal file
11
themes/cosmo.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/cyborg.css
Normal file
11
themes/cyborg.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/darkly.css
Normal file
11
themes/darkly.css
Normal file
File diff suppressed because one or more lines are too long
0
themes/default.css
Normal file
0
themes/default.css
Normal file
11
themes/flatly.css
Normal file
11
themes/flatly.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/journal.css
Normal file
11
themes/journal.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/lumen.css
Normal file
11
themes/lumen.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/paper.css
Normal file
11
themes/paper.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/readable.css
Normal file
11
themes/readable.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/sandstone.css
Normal file
11
themes/sandstone.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/simplex.css
Normal file
11
themes/simplex.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/slate.css
Normal file
11
themes/slate.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/spacelab.css
Normal file
11
themes/spacelab.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/superhero.css
Normal file
11
themes/superhero.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/united.css
Normal file
11
themes/united.css
Normal file
File diff suppressed because one or more lines are too long
11
themes/yeti.css
Normal file
11
themes/yeti.css
Normal file
File diff suppressed because one or more lines are too long
|
@ -41,11 +41,14 @@ of each of the method.
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from os import walk, path
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.forms import ModelForm, Form
|
from django.forms import ModelForm, Form
|
||||||
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
||||||
from django.contrib.auth.password_validation import validate_password, password_validators_help_text_html
|
from django.contrib.auth.password_validation import validate_password, password_validators_help_text_html
|
||||||
from django.core.validators import MinLengthValidator
|
from django.core.validators import MinLengthValidator
|
||||||
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
from django.contrib.auth.models import Group, Permission
|
from django.contrib.auth.models import Group, Permission
|
||||||
|
@ -1040,3 +1043,17 @@ class InitialRegisterForm(forms.Form):
|
||||||
if self.cleaned_data["register_machine"]:
|
if self.cleaned_data["register_machine"]:
|
||||||
if self.mac_address and self.nas_type:
|
if self.mac_address and self.nas_type:
|
||||||
self.user.autoregister_machine(self.mac_address, self.nas_type)
|
self.user.autoregister_machine(self.mac_address, self.nas_type)
|
||||||
|
|
||||||
|
|
||||||
|
class ThemeForm(FormRevMixin, forms.Form):
|
||||||
|
"""Form to change the theme of a user.
|
||||||
|
"""
|
||||||
|
|
||||||
|
theme = forms.ChoiceField(widget=forms.Select())
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
_, _ ,themes = next(walk(path.join(settings.STATIC_ROOT, "css/themes")))
|
||||||
|
if not themes:
|
||||||
|
themes = ["default.css"]
|
||||||
|
super(ThemeForm, self).__init__(*args, **kwargs)
|
||||||
|
self.fields['theme'].choices = [(theme, theme) for theme in themes]
|
20
users/migrations/0095_user_theme.py
Normal file
20
users/migrations/0095_user_theme.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.29 on 2020-11-16 18:52
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0094_remove_user_profile_image'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='theme',
|
||||||
|
field=models.CharField(default='default.css', max_length=255),
|
||||||
|
),
|
||||||
|
]
|
|
@ -305,6 +305,7 @@ class User(
|
||||||
verbose_name=_("enable shortcuts on Re2o website"), default=True
|
verbose_name=_("enable shortcuts on Re2o website"), default=True
|
||||||
)
|
)
|
||||||
email_change_date = models.DateTimeField(auto_now_add=True)
|
email_change_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
theme = models.CharField(max_length=255, default="default.css")
|
||||||
|
|
||||||
USERNAME_FIELD = "pseudo"
|
USERNAME_FIELD = "pseudo"
|
||||||
REQUIRED_FIELDS = ["surname", "email"]
|
REQUIRED_FIELDS = ["surname", "email"]
|
||||||
|
@ -1963,6 +1964,14 @@ class User(
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.pseudo
|
return self.pseudo
|
||||||
|
|
||||||
|
@property
|
||||||
|
def theme_name(self):
|
||||||
|
"""Return the theme without the extension
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: name of theme
|
||||||
|
"""
|
||||||
|
return self.theme.split(".")[0]
|
||||||
|
|
||||||
class Adherent(User):
|
class Adherent(User):
|
||||||
"""Base re2o Adherent model, inherit from User. Add other attributes.
|
"""Base re2o Adherent model, inherit from User. Add other attributes.
|
||||||
|
|
|
@ -176,6 +176,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
{% trans "Edit the groups" %}
|
{% trans "Edit the groups" %}
|
||||||
</a>
|
</a>
|
||||||
{% acl_end %}
|
{% acl_end %}
|
||||||
|
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-theme' users.id %}">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
{% trans "Change theme" %}
|
||||||
|
</a>
|
||||||
{% history_button users text=True %}
|
{% history_button users text=True %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -345,6 +349,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
<dt>{% trans "Shortcuts enabled" %}</dt>
|
<dt>{% trans "Shortcuts enabled" %}</dt>
|
||||||
<dd>{{ users.shortcuts_enabled | tick }}</dd>
|
<dd>{{ users.shortcuts_enabled | tick }}</dd>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6 col-xs-12">
|
||||||
|
<dt>{% trans "Theme" %}</dt>
|
||||||
|
<dd>{{ request.user.theme_name }}</dd>
|
||||||
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -127,4 +127,5 @@ urlpatterns = [
|
||||||
url(r"^$", views.index, name="index"),
|
url(r"^$", views.index, name="index"),
|
||||||
url(r"^index_clubs/$", views.index_clubs, name="index-clubs"),
|
url(r"^index_clubs/$", views.index_clubs, name="index-clubs"),
|
||||||
url(r"^initial_register/$", views.initial_register, name="initial-register"),
|
url(r"^initial_register/$", views.initial_register, name="initial-register"),
|
||||||
|
url(r"^edit_theme/(?P<userid>[0-9]+)$", views.edit_theme, name="edit-theme"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -128,6 +128,7 @@ from .forms import (
|
||||||
ClubAdminandMembersForm,
|
ClubAdminandMembersForm,
|
||||||
GroupForm,
|
GroupForm,
|
||||||
InitialRegisterForm,
|
InitialRegisterForm,
|
||||||
|
ThemeForm
|
||||||
)
|
)
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -1593,3 +1594,27 @@ def initial_register(request):
|
||||||
request,
|
request,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@can_edit(User)
|
||||||
|
def edit_theme(request, user, userid):
|
||||||
|
"""View for editing base user informations.
|
||||||
|
Perform an acl check on user instance.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
request (django request): Standard django request.
|
||||||
|
user: User instance to edit
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Django User form.
|
||||||
|
|
||||||
|
"""
|
||||||
|
theme_form = ThemeForm(request.POST or None, initial={'theme':user.theme})
|
||||||
|
if theme_form.is_valid():
|
||||||
|
user.theme = theme_form.cleaned_data["theme"]
|
||||||
|
user.save()
|
||||||
|
messages.success(request, _("The theme was edited."))
|
||||||
|
|
||||||
|
return redirect(reverse("users:profil", kwargs={"userid": str(userid)}))
|
||||||
|
return form(
|
||||||
|
{"userform": theme_form, "action_name": _("Edit")}, "users/user.html", request,
|
||||||
|
)
|
Loading…
Reference in a new issue