mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-24 02:39:20 -05:00
theming refactor
moved server side for a better page loading experience and less javascript mess
This commit is contained in:
@@ -26,6 +26,12 @@ class DateWidget(forms.DateInput):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class UserPreferenceForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = UserPreference
|
||||
fields = ('theme',)
|
||||
|
||||
|
||||
class ExternalRecipeForm(forms.ModelForm):
|
||||
file_path = forms.CharField(disabled=True, required=False)
|
||||
storage = forms.ModelChoiceField(queryset=Storage.objects.all(), disabled=True, required=False)
|
||||
|
||||
24
cookbook/migrations/0013_userpreference.py
Normal file
24
cookbook/migrations/0013_userpreference.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 3.0.2 on 2020-02-13 22:15
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0012_auto_20200130_1116'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserPreference',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('theme', models.CharField(choices=[('BOOTSTRAP', 'Bootstrap'), ('DARKLY', 'Darkly'), ('FLATLY', 'Flatly')], default='BOOTSTRAP', max_length=128)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
26
cookbook/migrations/0014_auto_20200213_2332.py
Normal file
26
cookbook/migrations/0014_auto_20200213_2332.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 3.0.2 on 2020-02-13 22:32
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0013_userpreference'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='theme',
|
||||
field=models.CharField(choices=[('BOOTSTRAP', 'Bootstrap'), ('DARKLY', 'Darkly'), ('FLATLY', 'Flatly'), ('SUPERHERO', 'Superhero')], default='BOOTSTRAP', max_length=128),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, unique=True),
|
||||
),
|
||||
]
|
||||
21
cookbook/migrations/0015_auto_20200213_2334.py
Normal file
21
cookbook/migrations/0015_auto_20200213_2334.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.0.2 on 2020-02-13 22:34
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0014_auto_20200213_2332'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='user',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
25
cookbook/migrations/0016_auto_20200213_2335.py
Normal file
25
cookbook/migrations/0016_auto_20200213_2335.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 3.0.2 on 2020-02-13 22:35
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0015_auto_20200213_2334'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='userpreference',
|
||||
name='id',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='user',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -3,6 +3,18 @@ from django.utils.translation import gettext as _
|
||||
from django.db import models
|
||||
|
||||
|
||||
class UserPreference(models.Model):
|
||||
BOOTSTRAP = 'BOOTSTRAP'
|
||||
DARKLY = 'DARKLY'
|
||||
FLATLY = 'FLATLY'
|
||||
SUPERHERO = 'SUPERHERO'
|
||||
|
||||
THEMES = ((BOOTSTRAP, 'Bootstrap'), (DARKLY, 'Darkly'), (FLATLY, 'Flatly'), (SUPERHERO, 'Superhero'))
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
||||
theme = models.CharField(choices=THEMES, max_length=128, default=BOOTSTRAP)
|
||||
|
||||
|
||||
class Storage(models.Model):
|
||||
DROPBOX = 'DB'
|
||||
NEXTCLOUD = 'NEXTCLOUD'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load custom_tags %}
|
||||
|
||||
<html>
|
||||
<head>
|
||||
@@ -18,31 +19,11 @@
|
||||
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
|
||||
|
||||
<!-- Bootstrap 4 -->
|
||||
<link id="id_main_css" rel="stylesheet"
|
||||
href="{% static 'themes/darkly.min.css' %}">
|
||||
<link id="id_main_css" href="{% theme_url request %}" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.js"
|
||||
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function getCookieValue(a) {
|
||||
let b = document.cookie.match('(^|[^;]+)\\s*' + a + '\\s*=\\s*([^;]+)');
|
||||
return b ? b.pop() : '';
|
||||
}
|
||||
|
||||
let theme_list = ['{% static 'themes/bootstrap.min.css' %}', '{% static 'themes/flatly.min.css' %}', '{% static 'themes/superhero.min.css' %}'];
|
||||
|
||||
let css = $('#id_main_css');
|
||||
let theme = getCookieValue('theme');
|
||||
if (theme !== "" && theme_list.includes(theme)) {
|
||||
css.attr('href', theme);
|
||||
} else {
|
||||
css.attr('href', '{% static 'themes/bootstrap.min.css' %}');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
|
||||
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
|
||||
crossorigin="anonymous"></script>
|
||||
@@ -161,15 +142,6 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<!-- Navbar theming, run before content to avoid flickering -->
|
||||
<script type="text/javascript">
|
||||
let nav_color = getCookieValue('color');
|
||||
if (nav_color !== "") {
|
||||
$('#id_main_nav').attr('class', 'navbar navbar-expand-lg navbar-dark bg-' + nav_color)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
{% for message in messages %}
|
||||
@@ -185,6 +157,8 @@
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block script %}
|
||||
{% endblock script %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{% trans 'Settings' %}{% endblock %}
|
||||
@@ -40,57 +41,13 @@
|
||||
|
||||
<h4><i class="fas fa-palette"></i>{% trans 'Style' %}</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<label>
|
||||
{% trans 'Choose Theme' %}
|
||||
<select class="form-control" id="id_select_theme" onchange="changeTheme()">
|
||||
<option value="{% static 'themes/bootstrap.min.css' %}">{% trans 'Default' %}</option>
|
||||
<option value="{% static 'themes/flatly.min.css' %}">Flatly</option>
|
||||
<!--<option value="{% static 'themes/darkly.min.css' %}">Darkly</option>-->
|
||||
<option value="{% static 'themes/superhero.min.css' %}">Superhero</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<form action="." method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
</form>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<label>
|
||||
{% trans 'Choose Navigation Color' %}
|
||||
<select class="form-control" id="id_select_color" onchange="changeNavColor()">
|
||||
<option value="primary">Primary</option>
|
||||
<option value="secondary">Secondary</option>
|
||||
<option value="info">Info</option>
|
||||
<option value="success">Success</option>
|
||||
<option value="warning">Warning</option>
|
||||
<option value="danger">Danger</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<script type="text/javascript">
|
||||
if (theme !== "") {
|
||||
$('#id_select_theme').val(theme)
|
||||
}
|
||||
if (nav_color !== "") {
|
||||
$('#id_select_color').val(nav_color)
|
||||
}
|
||||
|
||||
function changeTheme() {
|
||||
let theme = $('#id_select_theme').val();
|
||||
document.cookie = "theme=" + theme + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";
|
||||
location.reload();
|
||||
}
|
||||
|
||||
function changeNavColor() {
|
||||
let color = $('#id_select_color').val();
|
||||
document.cookie = "color=" + color + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -2,6 +2,9 @@ from django import template
|
||||
import markdown as md
|
||||
import bleach
|
||||
from bleach_whitelist import markdown_tags, markdown_attrs
|
||||
from django.templatetags.static import static
|
||||
|
||||
from cookbook.models import UserPreference
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@@ -14,3 +17,20 @@ def get_class(value):
|
||||
@register.filter()
|
||||
def markdown(value):
|
||||
return bleach.clean(md.markdown(value, extensions=['markdown.extensions.fenced_code']), markdown_tags, markdown_attrs)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def theme_url(request):
|
||||
try:
|
||||
themes = {
|
||||
UserPreference.BOOTSTRAP: 'themes/bootstrap.min.css',
|
||||
UserPreference.FLATLY: 'themes/flatly.min.css',
|
||||
UserPreference.DARKLY: 'themes/darkly.min.css',
|
||||
UserPreference.SUPERHERO: 'themes/superhero.min.css',
|
||||
}
|
||||
if request.user.userpreference.theme in themes:
|
||||
return static(themes[request.user.userpreference.theme])
|
||||
else:
|
||||
raise AttributeError
|
||||
except AttributeError:
|
||||
return static('themes/bootstrap.min.css')
|
||||
|
||||
@@ -145,4 +145,19 @@ def shopping_list(request):
|
||||
|
||||
@login_required
|
||||
def settings(request):
|
||||
return render(request, 'settings.html', {})
|
||||
up = request.user.userpreference
|
||||
|
||||
if request.method == "POST":
|
||||
form = UserPreferenceForm(request.POST)
|
||||
if form.is_valid():
|
||||
if not up:
|
||||
up = UserPreference(user=request.user)
|
||||
up.theme = form.cleaned_data['theme']
|
||||
up.save()
|
||||
|
||||
if up:
|
||||
form = UserPreferenceForm(instance=up)
|
||||
else:
|
||||
form = UserPreferenceForm()
|
||||
|
||||
return render(request, 'settings.html', {'form': form})
|
||||
|
||||
Reference in New Issue
Block a user