diff --git a/cookbook/migrations/0207_space_logo_color_128_space_logo_color_144_and_more.py b/cookbook/migrations/0207_space_logo_color_128_space_logo_color_144_and_more.py
new file mode 100644
index 00000000..6c3adbf5
--- /dev/null
+++ b/cookbook/migrations/0207_space_logo_color_128_space_logo_color_144_and_more.py
@@ -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'),
+ ),
+ ]
diff --git a/cookbook/models.py b/cookbook/models.py
index f091b8a4..0614c974 100644
--- a/cookbook/models.py
+++ b/cookbook/models.py
@@ -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)
@@ -1344,6 +1352,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'
diff --git a/cookbook/static/assets/favicon-16x16.png b/cookbook/static/assets/favicon-16x16.png
deleted file mode 100644
index 2ed29e2c..00000000
Binary files a/cookbook/static/assets/favicon-16x16.png and /dev/null differ
diff --git a/cookbook/static/assets/favicon.svg b/cookbook/static/assets/favicon.svg
deleted file mode 100644
index bcce5ce8..00000000
--- a/cookbook/static/assets/favicon.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
diff --git a/cookbook/static/assets/safari-pinned-tab.svg b/cookbook/static/assets/logo_black.svg
similarity index 100%
rename from cookbook/static/assets/safari-pinned-tab.svg
rename to cookbook/static/assets/logo_black.svg
diff --git a/cookbook/static/assets/logo_color_128.png b/cookbook/static/assets/logo_color_128.png
new file mode 100644
index 00000000..544e05c8
Binary files /dev/null and b/cookbook/static/assets/logo_color_128.png differ
diff --git a/cookbook/static/assets/logo_color144.png b/cookbook/static/assets/logo_color_144.png
similarity index 100%
rename from cookbook/static/assets/logo_color144.png
rename to cookbook/static/assets/logo_color_144.png
diff --git a/cookbook/static/assets/apple-touch-icon.png b/cookbook/static/assets/logo_color_180.png
similarity index 100%
rename from cookbook/static/assets/apple-touch-icon.png
rename to cookbook/static/assets/logo_color_180.png
diff --git a/cookbook/static/assets/logo_color_192.png b/cookbook/static/assets/logo_color_192.png
new file mode 100644
index 00000000..6ed65212
Binary files /dev/null and b/cookbook/static/assets/logo_color_192.png differ
diff --git a/cookbook/static/assets/favicon-32x32.png b/cookbook/static/assets/logo_color_32.png
similarity index 100%
rename from cookbook/static/assets/favicon-32x32.png
rename to cookbook/static/assets/logo_color_32.png
diff --git a/cookbook/static/assets/logo_color512.png b/cookbook/static/assets/logo_color_512.png
similarity index 100%
rename from cookbook/static/assets/logo_color512.png
rename to cookbook/static/assets/logo_color_512.png
diff --git a/cookbook/static/assets/logo_color.svg b/cookbook/static/assets/logo_color_svg.svg
similarity index 100%
rename from cookbook/static/assets/logo_color.svg
rename to cookbook/static/assets/logo_color_svg.svg
diff --git a/cookbook/templates/base.html b/cookbook/templates/base.html
index db70ed89..6c5f425d 100644
--- a/cookbook/templates/base.html
+++ b/cookbook/templates/base.html
@@ -3,6 +3,8 @@
{% load theming_tags %}
{% load custom_tags %}
+{% theme_values request as theme_values %}
+
{% block title %}
@@ -11,23 +13,18 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
-
-
+
diff --git a/cookbook/templatetags/theming_tags.py b/cookbook/templatetags/theming_tags.py
index 81543e79..6358f016 100644
--- a/cookbook/templatetags/theming_tags.py
+++ b/cookbook/templatetags/theming_tags.py
@@ -8,6 +8,33 @@ from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM
register = template.Library()
+@register.simple_tag
+def theme_values(request):
+ # TODO move all theming values to this tag to prevent double queries
+ 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'),
+ }
+ space = None
+ if request.space:
+ space = request.space
+ if UNAUTHENTICATED_THEME_FROM_SPACE > 0: # TODO load unauth space setting on boot in settings.py and use them here
+ with scopes_disabled():
+ space = Space.objects.filter(id=UNAUTHENTICATED_THEME_FROM_SPACE).first()
+
+ for logo in list(tv.keys()):
+ print(f'looking for {logo} in {space} has logo {getattr(space, logo, None)}')
+ if logo.startswith('logo_color_') and getattr(space, logo, None):
+ tv[logo] = getattr(space, logo).file.url
+
+ return tv
+
+
@register.simple_tag
def theme_url(request):
themes = {
@@ -20,7 +47,7 @@ def theme_url(request):
}
if not request.user.is_authenticated:
- if UNAUTHENTICATED_THEME_FROM_SPACE > 0: # TODO load unauth space setting on boot in settings.py and use them here
+ if UNAUTHENTICATED_THEME_FROM_SPACE > 0: # TODO load unauth space setting on boot in settings.py and use them here
with scopes_disabled():
return static(themes[Space.objects.filter(id=UNAUTHENTICATED_THEME_FROM_SPACE).first().space_theme])
else:
diff --git a/cookbook/urls.py b/cookbook/urls.py
index 1b1e6548..9566541a 100644
--- a/cookbook/urls.py
+++ b/cookbook/urls.py
@@ -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 = (
diff --git a/cookbook/views/views.py b/cookbook/views/views.py
index dc8d9f10..328ea65e 100644
--- a/cookbook/views/views.py
+++ b/cookbook/views/views.py
@@ -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', {})