Skip to content

Commit 682ea08

Browse files
committed
feat: added styling for treebwidget, fixed jump on click and dont show expand when no children presented
1 parent 1133ed8 commit 682ea08

5 files changed

Lines changed: 93 additions & 2 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,15 @@ MIDDLEWARE = [
120120
]
121121
```
122122

123+
Enable Django i18n URLs so `{% url 'set_language' %}` is available for the navigation language picker:
124+
```python
125+
from django.urls import include, path
126+
127+
urlpatterns = [
128+
path("i18n/", include("django.conf.urls.i18n")),
129+
]
130+
```
131+
123132
## 🔍 Audit Logging
124133

125134
Built-in optional audit app that automatically tracks all admin create, update, delete, and bulk operations with field-level diffs, snapshots, and request grouping. Just add `"django_smartbase_admin.audit"` to `INSTALLED_APPS` and run migrations.

src/django_smartbase_admin/engine/admin_base_view.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ def get_color_scheme_context(self, request):
215215
"color_scheme_form": color_scheme_form,
216216
}
217217

218+
def get_language_form_context(self, request):
219+
if len(settings.LANGUAGES) <= 1:
220+
return {"language_form": None}
221+
from django_smartbase_admin.views.user_config_view import LanguageForm
222+
223+
return {"language_form": LanguageForm(request=request)}
224+
218225
def get_add_label(
219226
self, request: HttpRequest, object_id: str | None = None
220227
) -> str | None:
@@ -269,6 +276,7 @@ def get_global_context(
269276
}
270277
),
271278
**self.get_color_scheme_context(request),
279+
**self.get_language_form_context(request),
272280
}
273281

274282
def get_model_path(self) -> str:

src/django_smartbase_admin/templates/sb_admin/navigation.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,17 @@
153153
</svg>
154154
{% trans 'Change password' %}
155155
</li>
156+
{% if language_form %}
157+
{% block language_picker %}
158+
<li class="border-t border-dark-100 pt-8">
159+
<form method="post" action="{% url 'set_language' %}" id="language-form" onchange="this.submit()">
160+
{% csrf_token %}
161+
{{ language_form.next }}
162+
{{ language_form.language }}
163+
</form>
164+
</li>
165+
{% endblock %}
166+
{% endif %}
156167
{% block color_scheme %}
157168
<li class="border-t border-dark-100 pt-8">
158169
<form hx-post="{% url 'sb_admin:color_scheme' %}" hx-trigger="change" hx-swap="none" id="color-schema-form" class="js-color-scheme-picker">

src/django_smartbase_admin/templates/sb_admin/widgets/radio_dropdown.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
data-bs-toggle="dropdown"
88
aria-expanded="false"
99
data-bs-offset="[0, 8]"
10-
class="btn px-10 font-normal w-full border-dark-300"
10+
class="btn px-10 font-normal w-full border-dark-300 {{ widget.attrs.button_class|default:'' }}"
1111
>
1212
<span id="{{ widget.attrs.id }}-value" class="js-dropdown-label flex gap-8">{{ widget.form_field.empty_label }}</span>
1313
<svg class="ml-8 no-rotate text-dark">

src/django_smartbase_admin/views/user_config_view.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from django import forms
2+
from django.conf import settings
23
from django.http import HttpResponse
4+
from django.templatetags.static import static
5+
from django.utils import translation
36
from django.utils.html import format_html
7+
from django.utils.translation import gettext_lazy as _
48
from django.views.generic import FormView
59

610
from django_smartbase_admin.admin.admin_base import SBAdminBaseFormInit
@@ -24,7 +28,9 @@ class Meta:
2428
model = SBAdminUserConfiguration
2529
fields = ("color_scheme",)
2630
widgets = {
27-
"color_scheme": SBAdminRadioDropdownWidget(),
31+
"color_scheme": SBAdminRadioDropdownWidget(
32+
attrs={"button_class": "shadow-none"}
33+
),
2834
}
2935
required = []
3036

@@ -52,3 +58,60 @@ def form_valid(self, form):
5258
sb_admin_user_config.color_scheme = instance.color_scheme
5359
sb_admin_user_config.save(update_fields=["color_scheme"])
5460
return HttpResponse(status=200)
61+
62+
class LanguageForm(SBAdminBaseFormInit, forms.Form):
63+
language = forms.ChoiceField(
64+
label=_("Language"),
65+
choices=(),
66+
widget=SBAdminRadioDropdownWidget(attrs={"button_class": "shadow-none"}),
67+
)
68+
next = forms.CharField(widget=forms.HiddenInput(), required=False)
69+
70+
@staticmethod
71+
def get_flag_static_path(lang_code: str) -> str:
72+
base = lang_code.split("-", 1)[0]
73+
return static(f"sb_admin/images/flags/{base}.png")
74+
75+
@classmethod
76+
def resolve_active_language_code(cls, languages: list[tuple[str, str]]) -> str:
77+
codes = [code for code, _ in languages]
78+
if not codes:
79+
return translation.get_language()
80+
81+
current = translation.get_language()
82+
if current in codes:
83+
return current
84+
85+
current_base = current.split("-", 1)[0]
86+
for code in codes:
87+
if code == current_base or code.startswith(f"{current_base}-"):
88+
return code
89+
90+
default_language = settings.LANGUAGE_CODE
91+
if default_language in codes:
92+
return default_language
93+
94+
return codes[0]
95+
96+
def __init__(self, *args, **kwargs):
97+
request = kwargs.pop("request", None)
98+
super().__init__(*args, request=request, **kwargs)
99+
choices_formatted = []
100+
for lang_code, lang_name in settings.LANGUAGES:
101+
flag_src = self.get_flag_static_path(lang_code)
102+
choice_label = format_html(
103+
'<span class="inline-flex items-center gap-8">'
104+
'<img src="{}" alt="{}" class="w-24 h-18 border border-dark-200 rounded-xs" width="24" height="18" loading="lazy">'
105+
"<span>{}</span></span>",
106+
flag_src,
107+
lang_name,
108+
lang_name,
109+
)
110+
choices_formatted.append((lang_code, choice_label))
111+
self.fields["language"].choices = choices_formatted
112+
113+
if request is not None and not self.is_bound:
114+
self.fields["next"].initial = request.get_full_path()
115+
self.fields["language"].initial = self.resolve_active_language_code(
116+
list(settings.LANGUAGES)
117+
)

0 commit comments

Comments
 (0)