Skip to content

Commit 39eb056

Browse files
yassiYasser Toruno
andauthored
Grappelli support (#6)
* initial grappelli theme adapter (needs adjustment) * resolve h1 spacing issues with h1 and icon placements under grappelli * fix several issues with buttons and inputs and spacing * update docs readme and add grappelli hub image --------- Co-authored-by: Yasser Toruno <yasser@yassers-mbp.lan>
1 parent aa8aa41 commit 39eb056

7 files changed

Lines changed: 162 additions & 321 deletions

File tree

README.md

Lines changed: 10 additions & 275 deletions
Large diffs are not rendered by default.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
DJ CONTROL ROOM - Grappelli Theme Adapter (themes/grappelli.css)
3+
4+
Not loaded automatically. Opt in per panel via EXTRA_CSS:
5+
6+
DJ_<PANEL>_SETTINGS = {
7+
"EXTRA_CSS": ["dj_control_room_base/css/themes/grappelli.css"],
8+
}
9+
*/
10+
11+
/* Grappelli's palette is hardcoded (no CSS vars), copied here directly.
12+
!important since Grappelli has no dark mode and must beat design-system's
13+
`prefers-color-scheme` query. Tokens with no Grappelli equivalent just
14+
repeat the light defaults so they survive that query too. */
15+
:root {
16+
--dcr-color-text: #444444 !important;
17+
--dcr-color-text-muted: #9a9a9a !important;
18+
--dcr-color-text-inverse: #ffffff !important;
19+
20+
--dcr-color-bg: #ffffff !important;
21+
--dcr-color-bg-subtle: #eeeeee !important;
22+
--dcr-color-border: #cccccc !important;
23+
--dcr-color-muted: #9a9a9a !important;
24+
--dcr-color-muted-bg: rgba(154, 154, 154, 0.14) !important;
25+
26+
--dcr-color-accent: #309bbf !important;
27+
--dcr-color-accent-bg: rgba(48, 155, 191, 0.10) !important;
28+
29+
--dcr-color-danger: #bf3030 !important;
30+
--dcr-color-danger-bg: rgba(191, 48, 48, 0.10) !important;
31+
32+
/* No Grappelli equivalent - design-system's light defaults. */
33+
--dcr-color-success: #2e7d32 !important;
34+
--dcr-color-success-bg: #e8f5e9 !important;
35+
--dcr-color-warning: #b45309 !important;
36+
--dcr-color-warning-bg: #fffbeb !important;
37+
--dcr-color-info: #01579b !important;
38+
--dcr-color-info-bg: #e1f5fe !important;
39+
--dcr-color-purple: #7c3aed !important;
40+
--dcr-color-purple-bg: #ede9fe !important;
41+
--dcr-color-indigo: #4338ca !important;
42+
--dcr-color-indigo-bg: #e0e7ff !important;
43+
44+
/* Match Grappelli's tighter 2-5px radius scale. */
45+
--dcr-radius: 2px !important;
46+
--dcr-radius-md: 3px !important;
47+
--dcr-radius-lg: 3px !important;
48+
--dcr-radius-xl: 5px !important;
49+
}
50+
51+
/* Hardcoded dark bg, not a --dcr-* token - Grappelli never goes dark. */
52+
.dcr-bar-chart__bar {
53+
background: rgba(46, 125, 50, 0.40) !important;
54+
}
55+
56+
.dcr-btn {
57+
font-weight: bold !important;
58+
}
59+
60+
/* Grappelli styles a bare `button` selector (meant for its own tiny
61+
related-lookup popup icon) with a -25px left margin and a forced 25x25
62+
size. That leaks onto every dcr-* button (dcr-btn, dcr-tabs__tab,
63+
dcr-dropdown__item), shifting each one under its predecessor. No
64+
!important needed - `.dcr-panel .dcr-classname` already outspecifies a
65+
bare element selector. Margin-left/right only, so dcr-tabs__tab's own
66+
`margin-bottom: -1px` survives. */
67+
.dcr-panel .dcr-btn,
68+
.dcr-panel .dcr-tabs__tab,
69+
.dcr-panel .dcr-dropdown__item {
70+
margin-left: 0;
71+
margin-right: 0;
72+
height: auto;
73+
overflow: visible;
74+
vertical-align: baseline;
75+
}
76+
77+
/* dcr-dropdown__item needs its own width: 100% to fill its menu. */
78+
.dcr-panel .dcr-btn,
79+
.dcr-panel .dcr-tabs__tab {
80+
width: auto;
81+
}
82+
83+
/* dcr-copy-btn is a dcr-btn too, but needs its own position: absolute to
84+
overlay a code block. */
85+
.dcr-panel .dcr-btn:not(.dcr-copy-btn),
86+
.dcr-panel .dcr-tabs__tab,
87+
.dcr-panel .dcr-dropdown__item {
88+
position: static;
89+
}
90+
91+
/* Grappelli's `input[type=...]` rule out-specifies a single dcr-* class,
92+
crushing inputs to a bold 25px-tall, 118px-wide box. min-height (not
93+
height) neutralises it without breaking dcr-input-group__input's
94+
`height: 100%` flex-stretch. */
95+
.dcr-panel input[type="text"],
96+
.dcr-panel input[type="password"],
97+
.dcr-panel input[type="url"],
98+
.dcr-panel input[type="email"],
99+
.dcr-panel input[type="number"],
100+
.dcr-panel input:not([type]) {
101+
width: 100% !important;
102+
min-height: 42px !important;
103+
font-weight: 400 !important;
104+
line-height: 1.4 !important;
105+
overflow: visible !important;
106+
}
107+
108+
/* Split out so it doesn't clobber components with their own focus ring
109+
(e.g. dcr-inline-edit__input). */
110+
.dcr-panel input[type="text"]:not(:focus),
111+
.dcr-panel input[type="password"]:not(:focus),
112+
.dcr-panel input[type="url"]:not(:focus),
113+
.dcr-panel input[type="email"]:not(:focus),
114+
.dcr-panel input[type="number"]:not(:focus),
115+
.dcr-panel input:not([type]):not(:focus) {
116+
box-shadow: none !important;
117+
}
118+
119+
/* Resolve spacing issues with h1s in page headers. */
120+
h1.dcr-page-header__title {
121+
padding-top: 0 !important;
122+
padding-bottom: 0 !important;
123+
}

docs/configuration.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ Additional stylesheets to inject after the default bundle (or after nothing, if
7070
DJ_CONTROL_ROOM_BASE_SETTINGS = {
7171
"LOAD_DEFAULT_CSS": True,
7272
"EXTRA_CSS": [
73-
"my_panel/css/overrides.css", # resolved via staticfiles
74-
"https://cdn.example.com/theme.css", # used as-is
73+
"my_panel/css/overrides.css", # resolved via staticfiles
74+
"https://cdn.example.com/theme.css", # used as-is
7575
],
7676
}
7777
```
@@ -100,12 +100,8 @@ Currently available:
100100
|---|---|
101101
| `themes/unfold.css` | Projects using [django-unfold](https://github.com/unfoldadmin/django-unfold) as their admin skin. |
102102
| `themes/jazzmin.css` | Projects using [django-jazzmin](https://github.com/farridav/django-jazzmin) as their admin skin. |
103+
| `themes/grappelli.css` | Projects using [django-grappelli](https://github.com/sehmaschine/django-grappelli) as their admin skin. |
103104

104-
`themes/unfold.css` maps DCR's tokens onto [django-unfold](https://github.com/unfoldadmin/django-unfold)'s own CSS variables, so panels automatically pick up the host site's configured brand color. `themes/jazzmin.css` does the same for [django-jazzmin](https://github.com/farridav/django-jazzmin), tracking whichever Bootswatch theme (light or dark) is configured via `JAZZMIN_UI_TWEAKS["theme"]`. Both only touch tokens, never `dcr-*` component rules, and dark mode is handled automatically - no extra configuration needed beyond loading the stylesheet.
105-
106-
Because this is opt-in per panel rather than hub-wide, each panel you want themed needs its own `EXTRA_CSS` entry for now.
107-
108-
![Django Control Room running with the django-unfold admin theme](https://raw.githubusercontent.com/django-control-room/dj-control-room-base/main/images/dcr-base-unfold.png)
109105

110106
You can also make your own theme adapters easily by following the `unfold.css` or
111107
`jazzmin.css` examples. This works very well for any Tailwind CSS or Bootstrap
@@ -164,7 +160,6 @@ DJ_CONTROL_ROOM_BASE_SETTINGS = {
164160
# Panel-wide defaults (apply to any view not listed in SCOPE_PERMISSIONS)
165161
"ALLOWED_GROUPS": [],
166162
"REQUIRE_SUPERUSER": False,
167-
168163
"SCOPE_PERMISSIONS": {
169164
# Only superusers can reach the design-system view
170165
"design-system": {

docs/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ The only runtime dependency is Django. `dj-control-room` is optional and only ne
7676

7777
![Django Control Room running with the django-jazzmin admin theme](https://raw.githubusercontent.com/django-control-room/dj-control-room-base/main/images/dcr-base-jazzmin.png)
7878

79+
**django-grappelli support** - a [theme adapter](configuration.md#theme-adapters) maps panels onto Grappelli's own hardcoded palette, since Grappelli predates CSS custom properties and has no dark mode of its own.
80+
81+
![Django Control Room running with the django-grappelli admin theme](https://raw.githubusercontent.com/django-control-room/dj-control-room-base/main/images/dcr-base-grappelli.png)
82+
7983
See [Theme Adapters](themes.md) for the full gallery of supported admin skins.
8084

8185
---

docs/installation.md

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,55 +23,25 @@ pip install dj-control-room-base dj-control-room
2323

2424
## 2. Add to `INSTALLED_APPS`
2525

26-
=== "Standalone (library or panel only)"
27-
28-
```python
29-
INSTALLED_APPS = [
30-
"django.contrib.admin",
31-
"django.contrib.auth",
32-
"django.contrib.contenttypes",
33-
"django.contrib.sessions",
34-
"django.contrib.messages",
35-
"django.contrib.staticfiles",
36-
"dj_control_room_base",
37-
]
38-
```
39-
40-
=== "With Control Room hub"
41-
42-
```python
26+
```python
4327
INSTALLED_APPS = [
4428
"django.contrib.admin",
4529
"django.contrib.auth",
4630
"django.contrib.contenttypes",
4731
"django.contrib.sessions",
4832
"django.contrib.messages",
4933
"django.contrib.staticfiles",
50-
"dj_control_room", # hub dashboard
51-
"dj_control_room_base", # this panel / core library
34+
"dj_control_room_base", # this panel / core library
35+
# any panels you want to add go here
36+
"dj_control_room", # hub dashboard
5237
]
53-
```
38+
```
5439

5540
---
5641

5742
## 3. Include URLs
5843

59-
=== "Standalone"
60-
61-
```python
62-
# urls.py
63-
from django.contrib import admin
64-
from django.urls import path, include
65-
66-
urlpatterns = [
67-
path("admin/dj-control-room-base/", include("dj_control_room_base.urls")),
68-
path("admin/", admin.site.urls),
69-
]
70-
```
71-
72-
=== "With Control Room hub"
73-
74-
```python
44+
```python
7545
# urls.py
7646
from django.contrib import admin
7747
from django.urls import path, include
@@ -81,7 +51,7 @@ pip install dj-control-room-base dj-control-room
8151
path("admin/dj-control-room/", include("dj_control_room.urls")),
8252
path("admin/", admin.site.urls),
8353
]
84-
```
54+
```
8555

8656
The URL prefix (`admin/dj-control-room-base/`) can be changed to whatever fits your project. The admin sidebar entry will still redirect users to the correct view via the named URL `dj_control_room_base:index`.
8757

docs/themes.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ See [`ui_customisation`](https://django-jazzmin.readthedocs.io/ui_customisation/
5050

5151
---
5252

53+
## django-grappelli
54+
55+
[`django-grappelli`](https://github.com/sehmaschine/django-grappelli) support via `themes/grappelli.css`, matching its teal accent and boxy, light-only look.
56+
57+
```python
58+
DJ_MY_PANEL_SETTINGS = {
59+
"EXTRA_CSS": ["dj_control_room_base/css/themes/grappelli.css"],
60+
}
61+
```
62+
63+
![Django Control Room running with the django-grappelli admin theme](https://raw.githubusercontent.com/django-control-room/dj-control-room-base/main/images/dcr-base-grappelli.png)
64+
65+
---
66+
5367
## Build your own
5468

55-
Both adapters follow the same recipe: remap `--dcr-*` tokens to the host skin's own variables, with sensible fallbacks. This works well for any Tailwind CSS or Bootstrap admin skin that exposes its palette as CSS custom properties - use `unfold.css` or `jazzmin.css` as a starting point.
69+
Want to support another admin skin? Use `unfold.css`, `jazzmin.css`, or `grappelli.css` as a starting point and remap the `--dcr-*` tokens to match.

images/dcr-base-grappelli.png

434 KB
Loading

0 commit comments

Comments
 (0)