Skip to content

Commit badb964

Browse files
authored
fix: site icon/logo modes (#194)
1 parent 98ca4b3 commit badb964

File tree

9 files changed

+210
-17
lines changed

9 files changed

+210
-17
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,16 @@ UNFOLD = {
154154
"SITE_TITLE": None,
155155
"SITE_HEADER": None,
156156
"SITE_URL": "/",
157-
"SITE_ICON": lambda request: static("logo.svg"),
157+
# "SITE_ICON": lambda request: static("icon.svg"), # both modes, optimise for 32px height
158+
"SITE_ICON": {
159+
"light": lambda request: static("icon-light.svg"), # light mode
160+
"dark": lambda request: static("icon-dark.svg"), # dark mode
161+
},
162+
# "SITE_LOGO": lambda request: static("logo.svg"), # both modes, optimise for 32px height
163+
"SITE_LOGO": {
164+
"light": lambda request: static("logo-light.svg"), # light mode
165+
"dark": lambda request: static("logo-dark.svg"), # dark mode
166+
},
158167
"SITE_SYMBOL": "speed", # symbol from icon set
159168
"ENVIRONMENT": "sample_app.environment_callback",
160169
"DASHBOARD_CALLBACK": "sample_app.dashboard_callback",

src/unfold/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"SITE_URL": "/",
99
"SITE_ICON": None,
1010
"SITE_SYMBOL": None,
11+
"SITE_LOGO": None,
1112
"COLORS": {
1213
"primary": {
1314
"50": "250 245 255",

src/unfold/sites.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,16 @@ def each_context(self, request: HttpRequest) -> Dict[str, Any]:
5555
"form_classes": {
5656
"text_input": INPUT_CLASSES,
5757
},
58-
"logo": self._get_value(
59-
get_config(self.settings_name)["SIDEBAR"].get("logo"), request
58+
"site_logo": self._get_mode_images(
59+
get_config(self.settings_name)["SITE_LOGO"], request
6060
),
61-
"colors": get_config(self.settings_name)["COLORS"],
62-
"icon": self._get_value(
61+
"site_icon": self._get_mode_images(
6362
get_config(self.settings_name)["SITE_ICON"], request
6463
),
65-
"symbol": self._get_value(
64+
"site_symbol": self._get_value(
6665
get_config(self.settings_name)["SITE_SYMBOL"], request
6766
),
67+
"colors": get_config(self.settings_name)["COLORS"],
6868
"tab_list": self.get_tabs_list(request),
6969
"styles": [
7070
self._get_value(style, request)
@@ -283,6 +283,20 @@ def get_tabs_list(self, request: HttpRequest) -> List[Dict[str, Any]]:
283283

284284
return tabs
285285

286+
def _get_mode_images(
287+
self, images: Union[Dict[str, callable], callable, str], request: HttpRequest
288+
) -> Union[Dict[str, str], str, None]:
289+
if isinstance(images, dict):
290+
if "light" in images and "dark" in images:
291+
return {
292+
"light": self._get_value(images["light"], request),
293+
"dark": self._get_value(images["dark"], request),
294+
}
295+
296+
return None
297+
298+
return self._get_value(images, request)
299+
286300
def _call_permission_callback(
287301
self, callback: Union[str, Callable, None], request: HttpRequest
288302
):
@@ -303,7 +317,10 @@ def _get_value(
303317
if isinstance(instance, str):
304318
return instance
305319

306-
return instance(*args)
320+
if isinstance(instance, Callable):
321+
return instance(*args)
322+
323+
return None
307324

308325
def _replace_values(self, target: Dict, source: Dict, request: HttpRequest):
309326
for key in source.keys():

src/unfold/static/unfold/css/styles.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/unfold/templates/unfold/helpers/navigation.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
<nav id="nav-sidebar" class="bg-gray-50 border-r border-gray-200 flex flex-col fixed max-h-screen min-h-screen min-w-sidebar transition-width w-sidebar dark:bg-gray-900 dark:border-gray-800">
55
<div class="border-b border-gray-200 mb-5 py-3 dark:border-gray-800">
66
<div class="flex font-medium h-10 items-center px-6 text-gray-700 dark:text-gray-200">
7-
{% if logo %}
8-
<img src="{{ logo }}" alt="{% trans "Home" %}"/>
7+
{% if site_logo %}
8+
{% include "unfold/helpers/site_logo.html" %}
99
{% elif branding %}
1010
{% include "unfold/helpers/site_icon.html" %}
11-
12-
{{ branding }}
1311
{% endif %}
1412
</div>
1513
</div>
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
{% load i18n %}
22

3-
{% if icon %}
3+
{% if site_icon %}
44
<a href="{% url "admin:index" %}">
5-
<img src="{{ icon }}" class="h-8 mr-4" alt="{% trans "Home" %}"/>
5+
{% if site_icon.light and site_icon.dark %}
6+
<img src="{{ site_icon.dark }}" alt="{% trans 'Home' %}" class="h-8 hidden mr-4 dark:block"/>
7+
8+
<img src="{{ site_icon.light }}" alt="{% trans 'Home' %}" class="block h-8 mr-4 dark:hidden" />
9+
{% else %}
10+
<img src="{{ site_icon }}" class="h-8 mr-4" alt="{% trans 'Home' %}" />
11+
{% endif %}
612
</a>
713
{% else %}
814
<a href="{% url "admin:index" %}" class="bg-primary-600 flex h-8 items-center justify-center rounded-md mr-4 text-white text-xs w-8">
9-
<span class="material-symbols-outlined md-18">{% if symbol %}{{ symbol }}{% else %}settings{% endif %}</span>
15+
<span class="material-symbols-outlined md-18">{% if site_symbol %}{{ site_symbol }}{% else %}settings{% endif %}</span>
1016
</a>
1117
{% endif %}
18+
19+
{{ branding }}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{% load i18n %}
2+
3+
<a href="{% url "admin:index" %}">
4+
{% if site_logo.light and site_logo.dark %}
5+
<img src="{{ site_logo.dark }}" alt="{% trans 'Home' %}" class="h-8 hidden mr-4 dark:block"/>
6+
7+
<img src="{{ site_logo.light }}" alt="{% trans 'Home' %}" class="block h-8 mr-4 dark:hidden" />
8+
{% else %}
9+
<img src="{{ site_logo }}" class="h-8 mr-4" alt="{% trans 'Home' %}" />
10+
{% endif %}
11+
</a>

tests/test_environment.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ def test_incorrect_environment_callback(self):
3333
request = RequestFactory().get("/rand")
3434
request.user = AnonymousUser()
3535
context = admin_site.each_context(request)
36-
print(context)
3736
self.assertTrue("environment" not in context)
3837
get_config.cache_clear()
3938

@@ -50,7 +49,6 @@ def test_correct_environment_callback(self):
5049
request = RequestFactory().get("/rand")
5150
request.user = AnonymousUser()
5251
context = admin_site.each_context(request)
53-
print(context)
5452
self.assertTrue("environment" in context)
5553
self.assertEqual(context["environment"], ["Testing Environment", "warning"])
5654
get_config.cache_clear()

tests/test_site_branding.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
from django.contrib.auth.models import AnonymousUser
2+
from django.templatetags.static import static
3+
from django.test import TestCase
4+
from django.test.client import RequestFactory
5+
from django.test.utils import override_settings
6+
from unfold.settings import CONFIG_DEFAULTS, get_config
7+
from unfold.sites import UnfoldAdminSite
8+
9+
10+
class SiteBrandingTestCase(TestCase):
11+
@override_settings(
12+
UNFOLD={
13+
**CONFIG_DEFAULTS,
14+
**{
15+
"SITE_ICON": lambda request: static("icon.svg"),
16+
},
17+
}
18+
)
19+
def test_correct_callback_site_icon(self):
20+
admin_site = UnfoldAdminSite()
21+
request = RequestFactory().get("/rand")
22+
request.user = AnonymousUser()
23+
context = admin_site.each_context(request)
24+
self.assertEqual(context["site_icon"], "icon.svg")
25+
get_config.cache_clear()
26+
27+
@override_settings(
28+
UNFOLD={
29+
**CONFIG_DEFAULTS,
30+
**{
31+
"SITE_ICON": "hardcoded-icon.svg",
32+
},
33+
}
34+
)
35+
def test_correct_string_site_icon(self):
36+
admin_site = UnfoldAdminSite()
37+
request = RequestFactory().get("/rand")
38+
request.user = AnonymousUser()
39+
context = admin_site.each_context(request)
40+
self.assertEqual(context["site_icon"], "hardcoded-icon.svg")
41+
get_config.cache_clear()
42+
43+
@override_settings(
44+
UNFOLD={
45+
**CONFIG_DEFAULTS,
46+
**{
47+
"SITE_ICON": {
48+
"light": lambda request: static("icon-light.svg"),
49+
"dark": lambda request: static("icon-dark.svg"),
50+
}
51+
},
52+
}
53+
)
54+
def test_correct_mode_site_icon(self):
55+
admin_site = UnfoldAdminSite()
56+
request = RequestFactory().get("/rand")
57+
request.user = AnonymousUser()
58+
context = admin_site.each_context(request)
59+
self.assertDictEqual(
60+
context["site_icon"], {"light": "icon-light.svg", "dark": "icon-dark.svg"}
61+
)
62+
get_config.cache_clear()
63+
64+
@override_settings(
65+
UNFOLD={
66+
**CONFIG_DEFAULTS,
67+
**{
68+
"SITE_ICON": {
69+
"light": lambda request: static("icon.svg"),
70+
}
71+
},
72+
}
73+
)
74+
def test_incorrect_mode_site_icon(self):
75+
admin_site = UnfoldAdminSite()
76+
request = RequestFactory().get("/rand")
77+
request.user = AnonymousUser()
78+
context = admin_site.each_context(request)
79+
self.assertIsNone(context["site_icon"])
80+
get_config.cache_clear()
81+
82+
@override_settings(
83+
UNFOLD={
84+
**CONFIG_DEFAULTS,
85+
**{
86+
"SITE_LOGO": lambda request: static("logo.svg"),
87+
},
88+
}
89+
)
90+
def test_correct_callback_site_logo(self):
91+
admin_site = UnfoldAdminSite()
92+
request = RequestFactory().get("/rand")
93+
request.user = AnonymousUser()
94+
context = admin_site.each_context(request)
95+
self.assertEqual(context["site_logo"], "logo.svg")
96+
get_config.cache_clear()
97+
98+
@override_settings(
99+
UNFOLD={
100+
**CONFIG_DEFAULTS,
101+
**{
102+
"SITE_LOGO": "hardcoded-logo.svg",
103+
},
104+
}
105+
)
106+
def test_correct_string_site_logo(self):
107+
admin_site = UnfoldAdminSite()
108+
request = RequestFactory().get("/rand")
109+
request.user = AnonymousUser()
110+
context = admin_site.each_context(request)
111+
self.assertEqual(context["site_logo"], "hardcoded-logo.svg")
112+
get_config.cache_clear()
113+
114+
@override_settings(
115+
UNFOLD={
116+
**CONFIG_DEFAULTS,
117+
**{
118+
"SITE_LOGO": {
119+
"light": lambda request: static("logo-light.svg"),
120+
"dark": lambda request: static("logo-dark.svg"),
121+
}
122+
},
123+
}
124+
)
125+
def test_correct_mode_site_logo(self):
126+
admin_site = UnfoldAdminSite()
127+
request = RequestFactory().get("/rand")
128+
request.user = AnonymousUser()
129+
context = admin_site.each_context(request)
130+
self.assertDictEqual(
131+
context["site_logo"], {"light": "logo-light.svg", "dark": "logo-dark.svg"}
132+
)
133+
get_config.cache_clear()
134+
135+
@override_settings(
136+
UNFOLD={
137+
**CONFIG_DEFAULTS,
138+
**{
139+
"SITE_LOGO": {
140+
"light": lambda request: static("logo.svg"),
141+
}
142+
},
143+
}
144+
)
145+
def test_incorrect_mode_site_logo(self):
146+
admin_site = UnfoldAdminSite()
147+
request = RequestFactory().get("/rand")
148+
request.user = AnonymousUser()
149+
context = admin_site.each_context(request)
150+
self.assertIsNone(context["site_logo"])
151+
get_config.cache_clear()

0 commit comments

Comments
 (0)