Merge branch 'develop' into feature/shopping-ui

# Conflicts:
#	cookbook/models.py
#	vue/src/locales/en.json
This commit is contained in:
vabene1111
2024-01-08 06:45:56 +08:00
25 changed files with 1454 additions and 874 deletions

View File

@@ -0,0 +1,49 @@
# Generated by Django 4.2.7 on 2024-01-06 15:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0206_rename_sticky_navbar_userpreference_nav_sticky_and_more'),
]
operations = [
migrations.AddField(
model_name='space',
name='logo_color_128',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_128', to='cookbook.userfile'),
),
migrations.AddField(
model_name='space',
name='logo_color_144',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_144', to='cookbook.userfile'),
),
migrations.AddField(
model_name='space',
name='logo_color_180',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_180', to='cookbook.userfile'),
),
migrations.AddField(
model_name='space',
name='logo_color_192',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_192', to='cookbook.userfile'),
),
migrations.AddField(
model_name='space',
name='logo_color_32',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_32', to='cookbook.userfile'),
),
migrations.AddField(
model_name='space',
name='logo_color_512',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_512', to='cookbook.userfile'),
),
migrations.AddField(
model_name='space',
name='logo_color_svg',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_logo_color_svg', to='cookbook.userfile'),
),
]

View File

@@ -289,6 +289,14 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
nav_bg_color = models.CharField(max_length=8, default='', blank=True, )
nav_text_color = models.CharField(max_length=16, choices=NAV_TEXT_COLORS, default=BLANK)
logo_color_32 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_32')
logo_color_128 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_128')
logo_color_144 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_144')
logo_color_180 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_180')
logo_color_192 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_192')
logo_color_512 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_512')
logo_color_svg = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_svg')
created_by = models.ForeignKey(User, on_delete=models.PROTECT, null=True)
created_at = models.DateTimeField(auto_now_add=True)
message = models.CharField(max_length=512, default='', blank=True)
@@ -1346,6 +1354,9 @@ class UserFile(ExportModelOperationsMixin('user_files'), models.Model, Permissio
self.file_size_kb = round(self.file.size / 1000)
super(UserFile, self).save(*args, **kwargs)
def __str__(self):
return f'{self.name} (#{self.id})'
class Automation(ExportModelOperationsMixin('automations'), models.Model, PermissionModelMixin):
FOOD_ALIAS = 'FOOD_ALIAS'

View File

@@ -283,6 +283,13 @@ class SpaceSerializer(WritableNestedModelSerializer):
image = UserFileViewSerializer(required=False, many=False, allow_null=True)
nav_logo = UserFileViewSerializer(required=False, many=False, allow_null=True)
custom_space_theme = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_32 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_128 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_144 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_180 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_192 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_512 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_svg = UserFileViewSerializer(required=False, many=False, allow_null=True)
def get_user_count(self, obj):
return UserSpace.objects.filter(space=obj).count()
@@ -304,7 +311,8 @@ class SpaceSerializer(WritableNestedModelSerializer):
fields = (
'id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'user_count', 'recipe_count', 'file_size_mb',
'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color', 'use_plural',)
'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color', 'use_plural',
'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512', 'logo_color_svg',)
read_only_fields = (
'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing',
'demo',)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,41 +0,0 @@
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Logo" transform="matrix(0.637323,0,0,0.637323,-243.095,-716.725)">
<g id="Kreis" transform="matrix(1.44936,0,0,1.50279,387.258,1039.34)">
<ellipse cx="273.123" cy="324.015" rx="259.822" ry="250.584" style="fill:url(#_Linear1);"/>
<clipPath id="_clip2">
<ellipse cx="273.123" cy="324.015" rx="259.822" ry="250.584"/>
</clipPath>
<g clip-path="url(#_clip2)">
<g id="Shadow" transform="matrix(1.10322,0,0,1.064,-5.58287,50.5786)">
<path d="M156.285,427.208L389.554,660.477L668.803,495.551L374.012,200.761L156.285,427.208Z" style="fill:rgb(22,22,22);"/>
<g transform="matrix(1,0,0,1,-4.22105,0.775864)">
<path d="M208.628,178.613L485.935,455.919L590.027,364.63L296.923,71.526L294.175,138.989L208.628,178.613Z" style="fill:rgb(22,22,22);"/>
</g>
<g transform="matrix(1,0,0,1,-85.3876,27.8512)">
<path d="M310.385,145.641L587.692,422.948L590.392,361.357L297.288,68.253L294.175,138.989L310.385,145.641Z" style="fill:rgb(22,22,22);"/>
</g>
</g>
</g>
</g>
<g transform="matrix(1.471,0,0,1.471,406.537,1149.69)">
<path d="M256.049,220C286.222,219.994 312.656,207.31 329.388,194.134C346.35,180.754 370.899,183.406 384.611,200.1C407.129,227.376 420.598,261.944 420.598,299.53C420.598,361.08 382.604,437.101 329.764,463.706C307.035,475.15 283.466,480.586 256.098,480.599L256.098,480.599L256.049,480.599L256,480.599L256,480.599C228.632,480.586 205.063,475.15 182.334,463.706C129.494,437.101 91.5,361.08 91.5,299.53C91.5,261.944 104.969,227.376 127.487,200.1C141.199,183.406 165.748,180.754 182.71,194.134C199.442,207.31 225.876,219.994 256.049,220Z" style="fill:rgb(255,203,118);"/>
</g>
<g id="Flame-2" transform="matrix(0.965725,0,0,0.89175,164.497,436.391)">
<path d="M604.408,844.314C601.981,840.845 601.962,836.056 604.362,832.565C606.763,829.074 611.005,827.721 614.769,829.246C633.87,836.869 658.833,848.629 678.207,864.452C718.526,897.381 729.55,919.407 738.552,942.091C749.208,968.943 750.785,996.68 748.515,1016.08C742.018,1071.61 700.355,1117.5 641.034,1117.5C581.713,1117.5 534.493,1072.05 533.553,1016.08C532.986,982.372 543.985,955.443 555.988,936.22C558.982,931.437 564.594,929.469 569.609,931.444C574.623,933.419 577.757,938.831 577.215,944.58C575.493,956.716 574.362,969.372 574.932,979.484C576.863,1013.7 597.171,1022.5 618.083,1022.29C640.371,1022.08 662.925,1003.17 654.797,954.895C647.69,912.681 622.362,870.194 604.408,844.314Z" style="fill:rgb(255,111,0);"/>
<clipPath id="_clip3">
<path d="M604.408,844.314C601.981,840.845 601.962,836.056 604.362,832.565C606.763,829.074 611.005,827.721 614.769,829.246C633.87,836.869 658.833,848.629 678.207,864.452C718.526,897.381 729.55,919.407 738.552,942.091C749.208,968.943 750.785,996.68 748.515,1016.08C742.018,1071.61 700.355,1117.5 641.034,1117.5C581.713,1117.5 534.493,1072.05 533.553,1016.08C532.986,982.372 543.985,955.443 555.988,936.22C558.982,931.437 564.594,929.469 569.609,931.444C574.623,933.419 577.757,938.831 577.215,944.58C575.493,956.716 574.362,969.372 574.932,979.484C576.863,1013.7 597.171,1022.5 618.083,1022.29C640.371,1022.08 662.925,1003.17 654.797,954.895C647.69,912.681 622.362,870.194 604.408,844.314Z"/>
</clipPath>
<g clip-path="url(#_clip3)">
<g transform="matrix(1.28784,-0.270602,0.285942,1.59598,247.349,825.209)">
<path d="M255.004,46.957C279.547,58.545 306,85.447 313.307,120.161C325.437,177.791 291.571,193.789 262.496,192.403C215.889,190.181 200.194,153.246 231.326,108.9C250.631,81.401 232.663,36.408 255.004,46.957Z" style="fill:rgb(255,209,0);"/>
</g>
</g>
</g>
<g id="Hut" transform="matrix(1.521,0,0,1.521,393.566,1149.06)">
<path d="M228.197,408.524C222.698,408.524 217.813,406.688 214.024,403.619C211.776,401.794 210.92,398.752 211.888,396.024C212.856,393.295 215.437,391.472 218.332,391.472C232.214,391.4 256.112,391.396 256.112,391.396C256.112,391.396 280.009,391.4 293.891,391.472C296.786,391.472 299.367,393.295 300.335,396.024C301.303,398.752 300.447,401.794 298.199,403.619C294.41,406.688 289.526,408.524 284.027,408.524L228.197,408.524ZM217.24,378.877C214.208,378.877 211.3,377.671 209.158,375.525C207.015,373.379 205.814,370.469 205.82,367.436C205.831,361.119 205.842,354.539 205.842,354.539C205.842,350.423 203.097,346.814 199.131,345.714C185.313,341.841 175.2,329.468 175.2,314.823C175.2,297.07 190.059,282.657 208.362,282.657C208.362,282.657 208.362,282.657 208.362,282.657C215.401,282.657 221.675,278.218 224.017,271.581C227.243,262.39 236.411,252.015 256,251.998L256,251.998L256.223,251.998L256.223,251.998C275.812,252.015 284.98,262.39 288.206,271.581C290.549,278.218 296.822,282.657 303.861,282.657C303.861,282.657 303.861,282.657 303.861,282.657C322.164,282.657 337.023,297.07 337.023,314.823C337.023,329.468 326.911,341.841 313.093,345.714C309.127,346.814 306.382,350.423 306.381,354.539C306.381,354.539 306.386,361.127 306.391,367.447C306.394,370.478 305.191,373.385 303.049,375.529C300.907,377.672 298.001,378.877 294.971,378.877C275.615,378.877 236.604,378.877 217.24,378.877Z" style="fill:rgb(22,22,22);"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2e-06,0,0,2e-06,3755.77,81.7179)"><stop offset="0" style="stop-color:rgb(39,39,39);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(108,108,108);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -3,6 +3,8 @@
{% load theming_tags %}
{% load custom_tags %}
{% theme_values request as theme_values %}
<html>
<head>
<title>{% block title %}
@@ -11,30 +13,25 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="robots" content="noindex,nofollow"/>
<link rel="shortcut icon" type="image/x-icon" href="{% static 'assets/favicon.svg' %}">
<link rel="shortcut icon" href="{% static 'assets/favicon.svg' %}">
<link rel="icon" type="image/png" href="{% static 'assets/favicon-32x32.png' %}" sizes="32x32">
<link rel="icon" type="image/png" href="{% static 'assets/favicon-16x16.png' %}" sizes="16x16">
<link rel="mask-icon" href="{% static 'assets/safari-pinned-tab.svg' %}" color="#161616">
<link rel="apple-touch-icon" href="{% static 'assets/apple-touch-icon.png' %}" sizes="180x180">
<link rel="icon" href="{{ theme_values.logo_color_svg }}">
<link rel="icon" href="{{ theme_values.logo_color_32 }}" sizes="32x32">
<link rel="icon" href="{{ theme_values.logo_color_128 }}" sizes="128x128">
<link rel="icon" href="{{ theme_values.logo_color_192 }}" sizes="192x192">
<link rel="apple-touch-icon" href="{{ theme_values.logo_color_180 }}" sizes="180x180">
<link rel="manifest" crossorigin="use-credentials" href="{% url 'web_manifest' %}">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
<meta name="msapplication-TileColor" content="{{ theme_values.nav_bg_color }}">
<meta name="msapplication-TileImage" content="{{ theme_values.logo_color_144 }}">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#161616">
<meta name="msapplication-TileColor" content="#161616">
<meta name="theme-color" content="#ffffff">
<meta name="theme-color" content="{{ theme_values.nav_bg_color }}">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<!-- Bootstrap 4 -->
<link id="id_main_css" href="{% theme_url request %}" rel="stylesheet">
{% if request.user.is_authenticated and request.space.custom_space_theme %}
<link id="id_custom_css" href="{% custom_theme request %}" rel="stylesheet">
<link id="id_main_css" href="{{ theme_values.theme }}" rel="stylesheet">
{% if theme_values.custom_theme %}
<link id="id_custom_css" href="{{ theme_values.custom_theme }}" rel="stylesheet">
{% endif %}
@@ -79,15 +76,15 @@
</head>
<body>
<nav class="navbar navbar-expand-lg {% nav_text_color request %}"
<nav class="navbar navbar-expand-lg {{ theme_values.nav_text_class }}"
id="id_main_nav"
style="{% sticky_nav request %}; background-color: {% nav_bg_color request %}">
style="{{ theme_values.sticky_nav }}; background-color: {{ theme_values.nav_bg_color }}">
{% if not request.user.userpreference.left_handed %}
{% if not request.user.is_authenticated or request.user.userpreference.nav_show_logo %}
<a class="navbar-brand p-0 me-2 justify-content-center" href="{% base_path request 'base' %}"
aria-label="Tandoor">
<img class="brand-icon" src="{% logo_url request %}" alt="Logo">
<img class="brand-icon" src="{{ theme_values.nav_logo }}" alt="Logo">
</a>
{% endif %}
{% endif %}
@@ -101,7 +98,7 @@
{% if not request.user.is_authenticated or request.user.userpreference.nav_show_logo %}
<a class="navbar-brand p-0 me-2 justify-content-center" href="{% base_path request 'base' %}"
aria-label="Tandoor">
<img class="brand-icon" src="{% logo_url request %}" alt="Logo">
<img class="brand-icon" src="{{ theme_values.nav_logo }}" alt="Logo">
</a>
{% endif %}
{% endif %}

View File

@@ -129,7 +129,7 @@
[](https://github.com/vabene1111/recipes)
[GitHub](https://github.com/vabene1111/recipes)
![{% trans 'This will become an image' %}]({% static 'assets/favicon.svg' %})
![{% trans 'This will become an image' %}]({% static 'assets/logo_color_svg.svg' %})
</code></pre>
<div style="text-align: center">
@@ -142,7 +142,7 @@
<div class="card-body">
<a href="https://github.com/vabene1111/recipes">https://github.com/vabene1111/recipes</a> <br/>
<a href="https://github.com/vabene1111/recipes">GitHub</a> <br/>
<img src="{% static 'assets/favicon.svg' %}" class="img-fluid" alt="{% trans 'This will become an image' %}"
<img src="{% static 'assets/logo_color_svg.svg' %}" class="img-fluid" alt="{% trans 'This will become an image' %}"
style="height: 3vw">
</div>

View File

@@ -3,15 +3,24 @@ from django.templatetags.static import static
from django_scopes import scopes_disabled
from cookbook.models import UserPreference, UserFile, Space
from recipes.settings import STICKY_NAV_PREF_DEFAULT
from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM_SPACE
register = template.Library()
@register.simple_tag
def theme_url(request):
if not request.user.is_authenticated:
return static('themes/tandoor.min.css')
def theme_values(request):
space = None
if request.space:
space = request.space
if not request.user.is_authenticated and UNAUTHENTICATED_THEME_FROM_SPACE > 0:
with scopes_disabled():
space = Space.objects.filter(id=UNAUTHENTICATED_THEME_FROM_SPACE).first()
return get_theming_values(space, request.user)
def get_theming_values(space, user):
themes = {
UserPreference.BOOTSTRAP: 'themes/bootstrap.min.css',
UserPreference.FLATLY: 'themes/flatly.min.css',
@@ -20,58 +29,48 @@ def theme_url(request):
UserPreference.TANDOOR: 'themes/tandoor.min.css',
UserPreference.TANDOOR_DARK: 'themes/tandoor_dark.min.css',
}
# if request.space.custom_space_theme:
# return request.space.custom_space_theme.file.url
nav_text_type_mapping = {Space.DARK: 'navbar-light',
Space.LIGHT: 'navbar-dark'} # inverted since navbar-dark means the background
if request.space.space_theme in themes:
return static(themes[request.space.space_theme])
else:
if request.user.userpreference.theme in themes:
return static(themes[request.user.userpreference.theme])
else:
raise AttributeError
tv = {
'logo_color_32': static('assets/logo_color_32.png'),
'logo_color_128': static('assets/logo_color_128.png'),
'logo_color_144': static('assets/logo_color_144.png'),
'logo_color_180': static('assets/logo_color_180.png'),
'logo_color_192': static('assets/logo_color_192.png'),
'logo_color_512': static('assets/logo_color_512.png'),
'logo_color_svg': static('assets/logo_color_svg.svg'),
'custom_theme': None,
'theme': static(themes[UserPreference.TANDOOR]),
'nav_logo': static('assets/brand_logo.png'),
'nav_bg_color': '#ddbf86',
'nav_text_class': 'navbar-light',
'sticky_nav': 'position: sticky; top: 0; left: 0; z-index: 1000;',
}
@register.simple_tag
def custom_theme(request):
if request.user.is_authenticated and request.space.custom_space_theme:
return request.space.custom_space_theme.file.url
if user.is_authenticated:
if user.userpreference.theme in themes:
tv['theme'] = static(themes[user.userpreference.theme])
if user.userpreference.nav_bg_color:
tv['nav_bg_color'] = user.userpreference.nav_bg_color
if user.userpreference.nav_text_color and user.userpreference.nav_text_color in nav_text_type_mapping:
tv['nav_text_class'] = nav_text_type_mapping[user.userpreference.nav_text_color]
if not user.userpreference.nav_sticky:
tv['sticky_nav'] = ''
@register.simple_tag
def logo_url(request):
if request.user.is_authenticated and getattr(getattr(request, "space", {}), 'nav_logo', None):
return request.space.nav_logo.file.url
else:
return static('assets/brand_logo.png')
@register.simple_tag
def nav_bg_color(request):
if not request.user.is_authenticated:
return '#ddbf86'
else:
if request.space.nav_bg_color:
return request.space.nav_bg_color
else:
return request.user.userpreference.nav_bg_color
@register.simple_tag
def nav_text_color(request):
type_mapping = {Space.DARK: 'navbar-light', Space.LIGHT: 'navbar-dark'} # inverted since navbar-dark means the background
if not request.user.is_authenticated:
return 'navbar-dark'
else:
if request.space.nav_text_color != Space.BLANK:
return type_mapping[request.space.nav_text_color]
else:
return type_mapping[request.user.userpreference.nav_text_color]
@register.simple_tag
def sticky_nav(request):
if (not request.user.is_authenticated and STICKY_NAV_PREF_DEFAULT) or (request.user.is_authenticated and request.user.userpreference.nav_sticky):
return 'position: sticky; top: 0; left: 0; z-index: 1000;'
else:
return ''
if space:
for logo in list(tv.keys()):
if logo.startswith('logo_color_') and getattr(space, logo, None):
tv[logo] = getattr(space, logo).file.url
if space.custom_space_theme:
tv['custom_theme'] = space.custom_space_theme.file.url
if space.space_theme in themes:
tv['theme'] = static(themes[space.space_theme])
if space.nav_logo:
tv['nav_logo'] = space.nav_logo.file.url
if space.nav_bg_color:
tv['nav_bg_color'] = space.nav_bg_color
if space.nav_text_color and space.nav_text_color in nav_text_type_mapping:
tv['nav_text_class'] = nav_text_type_mapping[space.nav_text_color]
return tv

View File

@@ -0,0 +1,36 @@
from django.contrib import auth
from django.templatetags.static import static
from cookbook.models import Space, UserPreference, UserFile
from cookbook.templatetags.theming_tags import theme_values, get_theming_values
def test_theming_function(space_1, u1_s1):
user = auth.get_user(u1_s1)
# uf = UserFile.objects.create(name='test', space=space_1, created_by=user) #TODO add file tests
assert get_theming_values(space_1, user)['theme'] == static('themes/tandoor.min.css')
assert get_theming_values(space_1, user)['nav_bg_color'] == '#ddbf86'
assert get_theming_values(space_1, user)['nav_text_class'] == 'navbar-light'
assert get_theming_values(space_1, user)['nav_logo'] == static('assets/brand_logo.png')
assert get_theming_values(space_1, user)['sticky_nav'] == 'position: sticky; top: 0; left: 0; z-index: 1000;'
user.userpreference.theme = UserPreference.TANDOOR_DARK
user.userpreference.nav_bg_color = '#ffffff'
user.userpreference.nav_text_color = UserPreference.LIGHT
user.userpreference.nav_sticky = False
user.userpreference.save()
assert get_theming_values(space_1, user)['theme'] == static('themes/tandoor_dark.min.css')
assert get_theming_values(space_1, user)['nav_bg_color'] == '#ffffff'
assert get_theming_values(space_1, user)['nav_text_class'] == 'navbar-dark'
assert get_theming_values(space_1, user)['sticky_nav'] == ''
space_1.space_theme = Space.BOOTSTRAP
space_1.nav_bg_color = '#000000'
space_1.nav_text_color = UserPreference.DARK
space_1.save()
assert get_theming_values(space_1, user)['theme'] == static('themes/bootstrap.min.css')
assert get_theming_values(space_1, user)['nav_bg_color'] == '#000000'
assert get_theming_values(space_1, user)['nav_text_class'] == 'navbar-light'

View File

@@ -162,8 +162,7 @@ urlpatterns = [
path('service-worker.js', (TemplateView.as_view(template_name="sw.js", content_type='application/javascript', )),
name='service_worker'),
path('manifest.json', (TemplateView.as_view(template_name="manifest.json", content_type='application/json', )),
name='web_manifest'),
path('manifest.json', views.web_manifest, name='web_manifest'),
]
generic_models = (

View File

@@ -1,3 +1,4 @@
import json
import os
import re
from datetime import datetime
@@ -14,8 +15,9 @@ from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.core.management import call_command
from django.db import models
from django.http import HttpResponseRedirect
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.templatetags.static import static
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.translation import gettext as _
@@ -335,13 +337,16 @@ def system(request):
database_message = _('Everything is fine!')
elif postgres_ver < postgres_current - 2:
database_status = 'danger'
database_message = _('PostgreSQL %(v)s is deprecated. Upgrade to a fully supported version!') % {'v': postgres_ver}
database_message = _('PostgreSQL %(v)s is deprecated. Upgrade to a fully supported version!') % {
'v': postgres_ver}
else:
database_status = 'info'
database_message = _('You are running PostgreSQL %(v1)s. PostgreSQL %(v2)s is recommended') % {'v1': postgres_ver, 'v2': postgres_current}
database_message = _('You are running PostgreSQL %(v1)s. PostgreSQL %(v2)s is recommended') % {
'v1': postgres_ver, 'v2': postgres_current}
else:
database_status = 'info'
database_message = _('This application is not running with a Postgres database backend. This is ok but not recommended as some features only work with postgres databases.')
database_message = _(
'This application is not running with a Postgres database backend. This is ok but not recommended as some features only work with postgres databases.')
secret_key = False if os.getenv('SECRET_KEY') else True
@@ -366,10 +371,12 @@ def system(request):
pass
else:
current_app = row
migration_info[current_app] = {'app': current_app, 'unapplied_migrations': [], 'applied_migrations': [], 'total': 0}
migration_info[current_app] = {'app': current_app, 'unapplied_migrations': [], 'applied_migrations': [],
'total': 0}
for key in migration_info.keys():
migration_info[key]['total'] = len(migration_info[key]['unapplied_migrations']) + len(migration_info[key]['applied_migrations'])
migration_info[key]['total'] = len(migration_info[key]['unapplied_migrations']) + len(
migration_info[key]['applied_migrations'])
return render(request, 'system.html', {
'gunicorn_media': settings.GUNICORN_MEDIA,
@@ -431,7 +438,8 @@ def invite_link(request, token):
link.used_by = request.user
link.save()
user_space = UserSpace.objects.create(user=request.user, space=link.space, internal_note=link.internal_note, invite_link=link, active=False)
user_space = UserSpace.objects.create(user=request.user, space=link.space,
internal_note=link.internal_note, invite_link=link, active=False)
if request.user.userspace_set.count() == 1:
user_space.active = True
@@ -472,6 +480,65 @@ def report_share_abuse(request, token):
return HttpResponseRedirect(reverse('index'))
def web_manifest(request):
icons = [
{"src": static("/assets/logo_color.svg"), "sizes": "any"},
{"src": static("/assets/logo_color144.png"), "type": "image/png", "sizes": "144x144"},
{"src": static("/assets/logo_color512.png"), "type": "image/png", "sizes": "512x512"}
]
if request.user.is_authenticated and getattr(request.space, 'logo_color_svg') and getattr(request.space, 'logo_color_144') and getattr(request.space, 'logo_color_512'):
icons = [
{"src": request.space.logo_color_svg.file.url, "sizes": "any"},
{"src": request.space.logo_color_144.file.url, "type": "image/png", "sizes": "144x144"},
{"src": request.space.logo_color_512.file.url, "type": "image/png", "sizes": "512x512"}
]
manifest_info = {
"name": "Tandoor Recipes",
"short_name": "Tandoor",
"description": _("Manage recipes, shopping list, meal plans and more."),
"icons": icons,
"start_url": "./search",
"background_color": "#ffcb76",
"display": "standalone",
"scope": ".",
"theme_color": "#ffcb76",
"shortcuts": [
{
"name": _("Plan"),
"short_name": _("Plan"),
"description": _("View your meal Plan"),
"url": "./plan"
},
{
"name": _("Books"),
"short_name": _("Books"),
"description": _("View your cookbooks"),
"url": "./books"
},
{
"name": _("Shopping"),
"short_name": _("Shopping"),
"description": _("View your shopping lists"),
"url": "./list/shopping-list/"
}
],
"share_target": {
"action": "/data/import/url",
"method": "GET",
"params": {
"title": "title",
"url": "url",
"text": "text"
}
}
}
return JsonResponse(manifest_info, json_dumps_params={'indent': 4})
def markdown_info(request):
return render(request, 'markdown_info.html', {})