django-spire 0.19.3__py3-none-any.whl → 0.19.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. django_spire/consts.py +1 -1
  2. django_spire/core/management/commands/spire_startapp_pkg/maps.py +14 -7
  3. django_spire/core/management/commands/spire_startapp_pkg/user_input.py +10 -7
  4. django_spire/core/static/django_spire/css/app-background.css +6 -0
  5. django_spire/core/static/django_spire/css/app-import.css +1 -0
  6. django_spire/core/static/django_spire/css/app-navigation.css +4 -0
  7. django_spire/core/static/django_spire/css/app-override.css +0 -0
  8. django_spire/core/static/django_spire/css/themes/ayu/app-dark.css +2 -0
  9. django_spire/core/static/django_spire/css/themes/ayu/app-light.css +2 -0
  10. django_spire/core/static/django_spire/css/themes/catppuccin/app-dark.css +2 -0
  11. django_spire/core/static/django_spire/css/themes/catppuccin/app-light.css +2 -0
  12. django_spire/core/static/django_spire/css/themes/default/app-dark.css +2 -0
  13. django_spire/core/static/django_spire/css/themes/default/app-light.css +2 -0
  14. django_spire/core/static/django_spire/css/themes/gruvbox/app-dark.css +2 -0
  15. django_spire/core/static/django_spire/css/themes/gruvbox/app-light.css +2 -0
  16. django_spire/core/static/django_spire/css/themes/material/app-dark.css +2 -0
  17. django_spire/core/static/django_spire/css/themes/material/app-light.css +2 -0
  18. django_spire/core/static/django_spire/css/themes/nord/app-dark.css +2 -0
  19. django_spire/core/static/django_spire/css/themes/nord/app-light.css +2 -0
  20. django_spire/core/static/django_spire/css/themes/one-dark/app-dark.css +2 -0
  21. django_spire/core/static/django_spire/css/themes/one-dark/app-light.css +2 -0
  22. django_spire/core/static/django_spire/css/themes/palenight/app-dark.css +2 -0
  23. django_spire/core/static/django_spire/css/themes/palenight/app-light.css +2 -0
  24. django_spire/core/static/django_spire/css/themes/rose-pine/app-dark.css +2 -0
  25. django_spire/core/static/django_spire/css/themes/rose-pine/app-light.css +2 -0
  26. django_spire/core/static/django_spire/css/themes/tokyo-night/app-dark.css +2 -0
  27. django_spire/core/static/django_spire/css/themes/tokyo-night/app-light.css +2 -0
  28. django_spire/core/templatetags/spire_core_tags.py +11 -0
  29. django_spire/theme/enums.py +0 -3
  30. django_spire/theme/models.py +0 -3
  31. django_spire/theme/tests/test_context_processor.py +6 -6
  32. django_spire/theme/tests/test_enums.py +0 -3
  33. django_spire/theme/tests/test_integration.py +2 -2
  34. django_spire/theme/tests/test_model.py +23 -24
  35. django_spire/theme/tests/test_views/test_json_views.py +4 -4
  36. {django_spire-0.19.3.dist-info → django_spire-0.19.5.dist-info}/METADATA +1 -1
  37. {django_spire-0.19.3.dist-info → django_spire-0.19.5.dist-info}/RECORD +40 -45
  38. django_spire/core/static/django_spire/css/themes/dracula/app-dark.css +0 -71
  39. django_spire/core/static/django_spire/css/themes/dracula/app-light.css +0 -66
  40. django_spire/core/static/django_spire/css/themes/oceanic-next/app-dark.css +0 -71
  41. django_spire/core/static/django_spire/css/themes/oceanic-next/app-light.css +0 -66
  42. django_spire/core/static/django_spire/css/themes/synthwave/app-dark.css +0 -71
  43. django_spire/core/static/django_spire/css/themes/synthwave/app-light.css +0 -66
  44. {django_spire-0.19.3.dist-info → django_spire-0.19.5.dist-info}/WHEEL +0 -0
  45. {django_spire-0.19.3.dist-info → django_spire-0.19.5.dist-info}/licenses/LICENSE.md +0 -0
  46. {django_spire-0.19.3.dist-info → django_spire-0.19.5.dist-info}/top_level.txt +0 -0
django_spire/consts.py CHANGED
@@ -1,4 +1,4 @@
1
- __VERSION__ = '0.19.3'
1
+ __VERSION__ = '0.19.5'
2
2
 
3
3
  MAINTENANCE_MODE_SETTINGS_NAME = 'MAINTENANCE_MODE'
4
4
 
@@ -29,6 +29,7 @@ class AppConfiguration:
29
29
  components: list[str],
30
30
  user_inputs: dict[str, str] | None = None
31
31
  ) -> AppConfiguration:
32
+ immediate_parent = components[-2] if len(components) > 2 else None
32
33
  parent_parts = components[1:-1] if len(components) > 1 else []
33
34
 
34
35
  app_name = (
@@ -49,8 +50,8 @@ class AppConfiguration:
49
50
  )
50
51
 
51
52
  default_label = (
52
- '_'.join(parent_parts).lower() + '_' + app_name.lower()
53
- if parent_parts
53
+ immediate_parent.lower() + '_' + app_name.lower()
54
+ if immediate_parent
54
55
  else app_name.lower()
55
56
  )
56
57
 
@@ -60,10 +61,16 @@ class AppConfiguration:
60
61
  else default_label
61
62
  )
62
63
 
64
+ default_db_table = (
65
+ '_'.join(parent_parts).lower() + '_' + app_name.lower()
66
+ if parent_parts
67
+ else app_name.lower()
68
+ )
69
+
63
70
  db_table = (
64
- user_inputs.get('db_table_name', default_label)
71
+ user_inputs.get('db_table_name', default_db_table)
65
72
  if user_inputs
66
- else default_label
73
+ else default_db_table
67
74
  )
68
75
 
69
76
  inherit_permissions = (
@@ -324,7 +331,7 @@ class ModelPermissions:
324
331
  user_inputs: dict[str, str] | None = None
325
332
  ) -> ModelPermissions:
326
333
  module = '.'.join(components)
327
- parent_parts = components[1:-1] if len(components) > 1 else []
334
+ immediate_parent = components[-2] if len(components) > 2 else None
328
335
 
329
336
  app_name = (
330
337
  user_inputs.get('app_name', components[-1])
@@ -344,8 +351,8 @@ class ModelPermissions:
344
351
  )
345
352
 
346
353
  default_permission_name = (
347
- '_'.join(parent_parts).lower() + '_' + app_name.lower()
348
- if parent_parts
354
+ immediate_parent.lower() + '_' + app_name.lower()
355
+ if immediate_parent
349
356
  else app_name.lower()
350
357
  )
351
358
 
@@ -49,7 +49,7 @@ class UserInputCollector:
49
49
  app_label = self._collect_app_label(components, app_name)
50
50
  model_name = self._collect_model_name(app_name)
51
51
  model_name_plural = self._collect_model_name_plural(model_name)
52
- db_table_name = self._collect_db_table_name(app_label)
52
+ db_table_name = self._collect_db_table_name(components, app_name) # Changed from app_label to components, app_name
53
53
  model_permission_path = self._collect_model_permission_path(app_path, model_name)
54
54
 
55
55
  permission_data = self._collect_permission_inheritance(components)
@@ -78,8 +78,8 @@ class UserInputCollector:
78
78
  :return: User-provided or default app label.
79
79
  """
80
80
 
81
- parent_parts = components[1:-1] if len(components) > 1 else []
82
- default = '_'.join(parent_parts).lower() + '_' + app_name.lower() if parent_parts else app_name.lower()
81
+ immediate_parent = components[-2] if len(components) > 2 else None
82
+ default = immediate_parent.lower() + '_' + app_name.lower() if immediate_parent else app_name.lower()
83
83
  return self._collect_input('Enter the app label', default, '3/8')
84
84
 
85
85
  def _collect_app_name(self, components: list[str]) -> str:
@@ -114,15 +114,18 @@ class UserInputCollector:
114
114
 
115
115
  return app_path
116
116
 
117
- def _collect_db_table_name(self, app_label: str) -> str:
117
+ def _collect_db_table_name(self, components: list[str], app_name: str) -> str:
118
118
  """
119
119
  Prompts the user for the database table name.
120
120
 
121
- :param app_label: App label to use as default.
121
+ :param components: List of app path components.
122
+ :param app_name: Name of the app.
122
123
  :return: User-provided or default database table name.
123
124
  """
124
125
 
125
- return self._collect_input('Enter the database table name', app_label, '6/8')
126
+ parent_parts = components[1:-1] if len(components) > 1 else []
127
+ default = '_'.join(parent_parts).lower() + '_' + app_name.lower() if parent_parts else app_name.lower()
128
+ return self._collect_input('Enter the database table name', default, '6/8')
126
129
 
127
130
  def _collect_input(self, prompt: str, default: str, step_number: str) -> str:
128
131
  """
@@ -183,7 +186,7 @@ class UserInputCollector:
183
186
  :return: Dictionary containing permission inheritance settings.
184
187
  """
185
188
 
186
- if len(components) <= 2:
189
+ if len(components) <= 1:
187
190
  return {'inherit_permissions': False, 'parent_permission_prefix': '', 'parent_model_instance_name': ''}
188
191
 
189
192
  if not self._should_inherit_permissions():
@@ -33,6 +33,8 @@
33
33
  --app-bg-alt-layer-three: var(--app-alt-layer-three);
34
34
  --app-bg-alt-layer-four: var(--app-alt-layer-four);
35
35
 
36
+ --app-bg-card-header: var(--app-card-header);
37
+
36
38
  --app-bg-side-navigation: var(--app-side-navigation-bg-color);
37
39
 
38
40
  --app-bg-top-navigation: var(--app-top-navigation-bg-color);
@@ -151,6 +153,10 @@
151
153
  background-color: var(--app-bg-alt-layer-four) !important;
152
154
  }
153
155
 
156
+ .bg-app-card-header {
157
+ background-color: var(--app-bg-card-header) !important;
158
+ }
159
+
154
160
  .bg-app-side-navigation, .bg-app-side-navigation-hover:hover {
155
161
  background-color: var(--app-bg-side-navigation) !important;
156
162
  }
@@ -10,3 +10,4 @@
10
10
  @import url('app-side-panel.css');
11
11
  @import url('app-text.css');
12
12
  @import url('app-template.css');
13
+ @import url('app-override.css');
@@ -73,6 +73,10 @@
73
73
  transition: background-color 0.2s ease, color 0.2s ease;
74
74
  }
75
75
 
76
+ .side-navigation a.active {
77
+ color: var(--app-side-navigation-link-color) !important;
78
+ }
79
+
76
80
  .side-navigation a:hover {
77
81
  color: var(--app-side-navigation-link-hover-color) !important;
78
82
  }
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #232834;
34
34
  --app-alt-layer-four: #343a46;
35
35
 
36
+ --app-card-header: #1f2430;
37
+
36
38
  --app-default-attribute-title-color: #bfbdb6;
37
39
  --app-default-button-text-color: #0f1419;
38
40
  --app-default-text-color: #bfbdb6;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #f7f8f9;
34
34
  --app-alt-layer-four: #eff1f3;
35
35
 
36
+ --app-card-header: #f0f0f0;
37
+
36
38
  --app-default-attribute-title-color: #828c99;
37
39
  --app-default-button-text-color: #fafafa;
38
40
  --app-default-text-color: #5c6773;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #393952;
34
34
  --app-alt-layer-four: #4a4b61;
35
35
 
36
+ --app-card-header: #313244;
37
+
36
38
  --app-default-attribute-title-color: #cdd6f4;
37
39
  --app-default-button-text-color: #1e1e2e;
38
40
  --app-default-text-color: #cdd6f4;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #a6adc8;
34
34
  --app-alt-layer-four: #9399b2;
35
35
 
36
+ --app-card-header: #dce0e8;
37
+
36
38
  --app-default-attribute-title-color: #6c6f85;
37
39
  --app-default-button-text-color: #eff1f5;
38
40
  --app-default-text-color: #4c4f69;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #292c2d;
34
34
  --app-alt-layer-four: #343738;
35
35
 
36
+ --app-card-header: #232526;
37
+
36
38
  --app-default-attribute-title-color: #ffffff;
37
39
  --app-default-button-text-color: #181818;
38
40
  --app-default-text-color: #ffffff;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #fcfcfc;
34
34
  --app-alt-layer-four: #f8f9fa;
35
35
 
36
+ --app-card-header: #f5f5f6;
37
+
36
38
  --app-default-attribute-title-color: #797c7d;
37
39
  --app-default-button-text-color: #ffffff;
38
40
  --app-default-text-color: #181818;
@@ -28,6 +28,8 @@
28
28
  --app-layer-three: #504945;
29
29
  --app-layer-four: #665c54;
30
30
 
31
+ --app-card-header: #3c3836;
32
+
31
33
  --app-alt-layer-one: #1d2021;
32
34
  --app-alt-layer-two: #32302f;
33
35
  --app-alt-layer-three: #45403d;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #e5d5b1;
34
34
  --app-alt-layer-four: #d0bfa5;
35
35
 
36
+ --app-card-header: #ebdbb2;
37
+
36
38
  --app-default-attribute-title-color: #665c54;
37
39
  --app-default-button-text-color: #fbf1c7;
38
40
  --app-default-text-color: #3c3836;
@@ -28,6 +28,8 @@
28
28
  --app-layer-three: #2d2d2d;
29
29
  --app-layer-four: #404040;
30
30
 
31
+ --app-card-header: #1e1e1e;
32
+
31
33
  --app-alt-layer-one: #0a0a0a;
32
34
  --app-alt-layer-two: #171717;
33
35
  --app-alt-layer-three: #262626;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #e8e8e8;
34
34
  --app-alt-layer-four: #d8d8d8;
35
35
 
36
+ --app-card-header: #f5f5f5;
37
+
36
38
  --app-default-attribute-title-color: #607d8b;
37
39
  --app-default-button-text-color: #ffffff;
38
40
  --app-default-text-color: #212121;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #3e4758;
34
34
  --app-alt-layer-four: #475164;
35
35
 
36
+ --app-card-header: #3b4252;
37
+
36
38
  --app-default-attribute-title-color: #eceff4;
37
39
  --app-default-button-text-color: #2e3440;
38
40
  --app-default-text-color: #eceff4;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #dfe5ef;
34
34
  --app-alt-layer-four: #c8d0df;
35
35
 
36
+ --app-card-header: #d8dee9;
37
+
36
38
  --app-default-attribute-title-color: #4c566a;
37
39
  --app-default-button-text-color: #eceff4;
38
40
  --app-default-text-color: #2e3440;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #333841;
34
34
  --app-alt-layer-four: #424855;
35
35
 
36
+ --app-card-header: #2c313c;
37
+
36
38
  --app-default-attribute-title-color: #abb2bf;
37
39
  --app-default-button-text-color: #21252b;
38
40
  --app-default-text-color: #abb2bf;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #eeeeef;
34
34
  --app-alt-layer-four: #e0e0e2;
35
35
 
36
+ --app-card-header: #e5e5e6;
37
+
36
38
  --app-default-attribute-title-color: #6c6f93;
37
39
  --app-default-button-text-color: #fafafa;
38
40
  --app-default-text-color: #383a42;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #3e4267;
34
34
  --app-alt-layer-four: #575c7c;
35
35
 
36
+ --app-card-header: #444267;
37
+
36
38
  --app-default-attribute-title-color: #a6accd;
37
39
  --app-default-button-text-color: #292d3e;
38
40
  --app-default-text-color: #a6accd;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #f8f9fc;
34
34
  --app-alt-layer-four: #f0f1f5;
35
35
 
36
+ --app-card-header: #e9eaef;
37
+
36
38
  --app-default-attribute-title-color: #8087a2;
37
39
  --app-default-button-text-color: #fafafa;
38
40
  --app-default-text-color: #4e5579;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #393748;
34
34
  --app-alt-layer-four: #524f67;
35
35
 
36
+ --app-card-header: #26233a;
37
+
36
38
  --app-default-attribute-title-color: #e0def4;
37
39
  --app-default-button-text-color: #191724;
38
40
  --app-default-text-color: #e0def4;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #e9dfd8;
34
34
  --app-alt-layer-four: #d6d2d5;
35
35
 
36
+ --app-card-header: #e6ddd6;
37
+
36
38
  --app-default-attribute-title-color: #797593;
37
39
  --app-default-button-text-color: #faf4ed;
38
40
  --app-default-text-color: #575279;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #292e42;
34
34
  --app-alt-layer-four: #3b4261;
35
35
 
36
+ --app-card-header: #24283b;
37
+
36
38
  --app-default-attribute-title-color: #c0caf5;
37
39
  --app-default-button-text-color: #1a1b26;
38
40
  --app-default-text-color: #c0caf5;
@@ -33,6 +33,8 @@
33
33
  --app-alt-layer-three: #f7f7f8;
34
34
  --app-alt-layer-four: #d6d6d8;
35
35
 
36
+ --app-card-header: #dfe0e5;
37
+
36
38
  --app-default-attribute-title-color: #6f7bb6;
37
39
  --app-default-button-text-color: #d5d6db;
38
40
  --app-default-text-color: #343b58;
@@ -79,6 +79,17 @@ def index(indexable: Sequence[U], index_value: int) -> U | Sequence[U]:
79
79
  return indexable
80
80
 
81
81
 
82
+ @register.filter(name='is_path')
83
+ def is_path(current: str, url: str) -> bool:
84
+ if not current or not url:
85
+ return False
86
+
87
+ if current == url:
88
+ return True
89
+
90
+ return url != '/' and current.startswith(url)
91
+
92
+
82
93
  @register.simple_tag()
83
94
  def generate_id() -> str:
84
95
  """
@@ -7,15 +7,12 @@ class ThemeFamily(StrEnum):
7
7
  AYU = 'ayu'
8
8
  CATPPUCCIN = 'catppuccin'
9
9
  DEFAULT = 'default'
10
- DRACULA = 'dracula'
11
10
  GRUVBOX = 'gruvbox'
12
11
  MATERIAL = 'material'
13
12
  NORD = 'nord'
14
- OCEANIC_NEXT = 'oceanic-next'
15
13
  ONE_DARK = 'one-dark'
16
14
  PALENIGHT = 'palenight'
17
15
  ROSE_PINE = 'rose-pine'
18
- SYNTHWAVE = 'synthwave'
19
16
  TOKYO_NIGHT = 'tokyo-night'
20
17
 
21
18
 
@@ -19,15 +19,12 @@ class Theme:
19
19
  ThemeFamily.AYU: 'Ayu',
20
20
  ThemeFamily.CATPPUCCIN: 'Catppuccin',
21
21
  ThemeFamily.DEFAULT: 'Default',
22
- ThemeFamily.DRACULA: 'Dracula',
23
22
  ThemeFamily.GRUVBOX: 'Gruvbox',
24
23
  ThemeFamily.MATERIAL: 'Material',
25
24
  ThemeFamily.NORD: 'Nord',
26
- ThemeFamily.OCEANIC_NEXT: 'Oceanic Next',
27
25
  ThemeFamily.ONE_DARK: 'One Dark Pro',
28
26
  ThemeFamily.PALENIGHT: 'Palenight',
29
27
  ThemeFamily.ROSE_PINE: 'Rose Pine',
30
- ThemeFamily.SYNTHWAVE: 'Synthwave',
31
28
  ThemeFamily.TOKYO_NIGHT: 'Tokyo Night',
32
29
  }
33
30
 
@@ -18,14 +18,14 @@ class ThemeContextProcessorTests(TestCase):
18
18
  request = self.factory.get('/')
19
19
  request.COOKIES = {}
20
20
 
21
- with patch('django_spire.conf.settings.DJANGO_SPIRE_DEFAULT_THEME', 'dracula-dark'):
21
+ with patch('django_spire.conf.settings.DJANGO_SPIRE_DEFAULT_THEME', 'gruvbox-dark'):
22
22
  context = theme_context(request)
23
23
 
24
- self.assertEqual(context['DJANGO_SPIRE_DEFAULT_THEME'], 'dracula-dark')
24
+ self.assertEqual(context['DJANGO_SPIRE_DEFAULT_THEME'], 'gruvbox-dark')
25
25
  self.assertIn('theme', context)
26
26
 
27
27
  data = context['theme']
28
- self.assertEqual(data['family'], 'dracula')
28
+ self.assertEqual(data['family'], 'gruvbox')
29
29
  self.assertEqual(data['mode'], 'dark')
30
30
 
31
31
  def test_theme_context_with_cookie(self) -> None:
@@ -45,11 +45,11 @@ class ThemeContextProcessorTests(TestCase):
45
45
  cookie_name = get_theme_cookie_name()
46
46
  request.COOKIES = {cookie_name: 'invalid-theme'}
47
47
 
48
- with patch('django_spire.conf.settings.DJANGO_SPIRE_DEFAULT_THEME', 'dracula-dark'):
48
+ with patch('django_spire.conf.settings.DJANGO_SPIRE_DEFAULT_THEME', 'gruvbox-dark'):
49
49
  context = theme_context(request)
50
50
 
51
51
  data = context['theme']
52
- self.assertEqual(data['family'], 'dracula')
52
+ self.assertEqual(data['family'], 'gruvbox')
53
53
  self.assertEqual(data['mode'], 'dark')
54
54
 
55
55
  def test_theme_context_path_setting(self) -> None:
@@ -70,7 +70,7 @@ class ThemeContextProcessorIntegrationTests(BaseTestCase):
70
70
 
71
71
  def test_theme_context_with_authenticated_client(self) -> None:
72
72
  cookie_name = get_theme_cookie_name()
73
- self.client.cookies[cookie_name] = 'dracula-dark'
73
+ self.client.cookies[cookie_name] = 'gruvbox-dark'
74
74
  response = self.client.get('/')
75
75
  self.assertEqual(response.status_code, 200)
76
76
 
@@ -11,15 +11,12 @@ class ThemeEnumTests(TestCase):
11
11
  'ayu',
12
12
  'catppuccin',
13
13
  'default',
14
- 'dracula',
15
14
  'gruvbox',
16
15
  'material',
17
16
  'nord',
18
- 'oceanic-next',
19
17
  'one-dark',
20
18
  'palenight',
21
19
  'rose-pine',
22
- 'synthwave',
23
20
  'tokyo-night'
24
21
  }
25
22
 
@@ -40,9 +40,9 @@ class ThemeIntegrationTests(BaseTestCase):
40
40
  self.assertEqual(response.status_code, 200)
41
41
 
42
42
  def test_theme_media_integration(self) -> None:
43
- theme = Theme(family=ThemeFamily.DRACULA, mode='dark')
43
+ theme = Theme(family=ThemeFamily.GRUVBOX, mode='dark')
44
44
  stylesheet = theme.stylesheet
45
45
 
46
46
  self.assertIn('django_spire/css/themes/', stylesheet)
47
- self.assertIn('dracula', stylesheet)
47
+ self.assertIn('gruvbox', stylesheet)
48
48
  self.assertIn('app-dark.css', stylesheet)
@@ -27,13 +27,13 @@ class ThemeModelTests(TestCase):
27
27
  self.assertIn(family, Theme.FAMILY_DISPLAY_NAMES)
28
28
 
29
29
  def test_theme_initialization_with_enums(self) -> None:
30
- theme = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
31
- self.assertEqual(theme.family, ThemeFamily.DRACULA)
30
+ theme = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
31
+ self.assertEqual(theme.family, ThemeFamily.GRUVBOX)
32
32
  self.assertEqual(theme.mode, ThemeMode.DARK)
33
33
 
34
34
  def test_theme_initialization_with_strings(self) -> None:
35
- theme = Theme(family='dracula', mode='dark')
36
- self.assertEqual(theme.family, ThemeFamily.DRACULA)
35
+ theme = Theme(family='gruvbox', mode='dark')
36
+ self.assertEqual(theme.family, ThemeFamily.GRUVBOX)
37
37
  self.assertEqual(theme.mode, ThemeMode.DARK)
38
38
 
39
39
  def test_theme_initialization_invalid_family(self) -> None:
@@ -43,16 +43,15 @@ class ThemeModelTests(TestCase):
43
43
 
44
44
  def test_theme_initialization_invalid_mode(self) -> None:
45
45
  with pytest.raises(ValueError) as ctx:
46
- Theme(family='dracula', mode='invalid-mode')
46
+ Theme(family='gruvbox', mode='invalid-mode')
47
47
  self.assertIn('Invalid theme mode', str(ctx.value))
48
48
 
49
49
  def test_from_string_valid(self) -> None:
50
50
  cases = [
51
51
  ('default-light', ThemeFamily.DEFAULT, ThemeMode.LIGHT),
52
- ('dracula-dark', ThemeFamily.DRACULA, ThemeMode.DARK),
52
+ ('gruvbox-dark', ThemeFamily.GRUVBOX, ThemeMode.DARK),
53
53
  ('one-dark-light', ThemeFamily.ONE_DARK, ThemeMode.LIGHT),
54
54
  ('tokyo-night-dark', ThemeFamily.TOKYO_NIGHT, ThemeMode.DARK),
55
- ('oceanic-next-light', ThemeFamily.OCEANIC_NEXT, ThemeMode.LIGHT),
56
55
  ]
57
56
 
58
57
  for string, family, mode in cases:
@@ -62,7 +61,7 @@ class ThemeModelTests(TestCase):
62
61
  self.assertEqual(theme.mode, mode)
63
62
 
64
63
  def test_from_string_empty_with_default(self) -> None:
65
- default = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
64
+ default = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
66
65
  theme = Theme.from_string('', default=default)
67
66
  self.assertEqual(theme, default)
68
67
 
@@ -72,7 +71,7 @@ class ThemeModelTests(TestCase):
72
71
  self.assertEqual(theme.mode, Theme.DEFAULT_MODE)
73
72
 
74
73
  def test_from_string_invalid_with_default(self) -> None:
75
- default = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
74
+ default = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
76
75
  theme = Theme.from_string('invalid', default=default)
77
76
  self.assertEqual(theme, default)
78
77
 
@@ -97,27 +96,27 @@ class ThemeModelTests(TestCase):
97
96
  self.assertEqual(default.mode, Theme.DEFAULT_MODE)
98
97
 
99
98
  def test_display_property(self) -> None:
100
- theme = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
101
- self.assertEqual(theme.display, 'Dracula - Dark')
99
+ theme = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
100
+ self.assertEqual(theme.display, 'Gruvbox - Dark')
102
101
 
103
102
  theme = Theme(family=ThemeFamily.ONE_DARK, mode=ThemeMode.LIGHT)
104
103
  self.assertEqual(theme.display, 'One Dark Pro - Light')
105
104
 
106
105
  def test_family_display_property(self) -> None:
107
- theme = Theme(family=ThemeFamily.OCEANIC_NEXT, mode=ThemeMode.DARK)
108
- self.assertEqual(theme.family_display, 'Oceanic Next')
106
+ theme = Theme(family=ThemeFamily.ONE_DARK, mode=ThemeMode.DARK)
107
+ self.assertEqual(theme.family_display, 'One Dark Pro')
109
108
 
110
109
  def test_is_dark_property(self) -> None:
111
- dark = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
110
+ dark = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
112
111
  self.assertTrue(dark.is_dark)
113
112
 
114
- light = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.LIGHT)
113
+ light = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.LIGHT)
115
114
  self.assertFalse(light.is_dark)
116
115
 
117
116
  def test_stylesheet_property(self) -> None:
118
117
  cases = [
119
118
  (ThemeFamily.DEFAULT, ThemeMode.LIGHT, 'django_spire/css/themes/default/app-light.css'),
120
- (ThemeFamily.DRACULA, ThemeMode.DARK, 'django_spire/css/themes/dracula/app-dark.css'),
119
+ (ThemeFamily.GRUVBOX, ThemeMode.DARK, 'django_spire/css/themes/gruvbox/app-dark.css'),
121
120
  (ThemeFamily.ONE_DARK, ThemeMode.LIGHT, 'django_spire/css/themes/one-dark/app-light.css'),
122
121
  (ThemeFamily.TOKYO_NIGHT, ThemeMode.DARK, 'django_spire/css/themes/tokyo-night/app-dark.css'),
123
122
  ]
@@ -130,7 +129,7 @@ class ThemeModelTests(TestCase):
130
129
  def test_value_property(self) -> None:
131
130
  cases = [
132
131
  (ThemeFamily.DEFAULT, ThemeMode.LIGHT, 'default-light'),
133
- (ThemeFamily.DRACULA, ThemeMode.DARK, 'dracula-dark'),
132
+ (ThemeFamily.GRUVBOX, ThemeMode.DARK, 'gruvbox-dark'),
134
133
  (ThemeFamily.ONE_DARK, ThemeMode.LIGHT, 'one-dark-light'),
135
134
  (ThemeFamily.TOKYO_NIGHT, ThemeMode.DARK, 'tokyo-night-dark'),
136
135
  ]
@@ -141,7 +140,7 @@ class ThemeModelTests(TestCase):
141
140
  self.assertEqual(theme.value, value)
142
141
 
143
142
  def test_to_dict(self) -> None:
144
- theme = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
143
+ theme = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
145
144
  result = theme.to_dict()
146
145
 
147
146
  keys = {
@@ -156,16 +155,16 @@ class ThemeModelTests(TestCase):
156
155
 
157
156
  self.assertEqual(set(result.keys()), keys)
158
157
 
159
- self.assertEqual(result['display'], 'Dracula - Dark')
160
- self.assertEqual(result['family'], 'dracula')
161
- self.assertEqual(result['family_display'], 'Dracula')
162
- self.assertEqual(result['full'], 'dracula-dark')
158
+ self.assertEqual(result['display'], 'Gruvbox - Dark')
159
+ self.assertEqual(result['family'], 'gruvbox')
160
+ self.assertEqual(result['family_display'], 'Gruvbox')
161
+ self.assertEqual(result['full'], 'gruvbox-dark')
163
162
  self.assertTrue(result['is_dark'])
164
163
  self.assertEqual(result['mode'], 'dark')
165
- self.assertEqual(result['stylesheet'], 'django_spire/css/themes/dracula/app-dark.css')
164
+ self.assertEqual(result['stylesheet'], 'django_spire/css/themes/gruvbox/app-dark.css')
166
165
 
167
166
  def test_theme_immutability(self) -> None:
168
- theme = Theme(family=ThemeFamily.DRACULA, mode=ThemeMode.DARK)
167
+ theme = Theme(family=ThemeFamily.GRUVBOX, mode=ThemeMode.DARK)
169
168
 
170
169
  with pytest.raises(AttributeError):
171
170
  theme.family = ThemeFamily.DEFAULT
@@ -50,7 +50,7 @@ class ThemeViewTests(TestCase):
50
50
  def test_set_theme_success(self) -> None:
51
51
  request = self.factory.post(
52
52
  '/django_spire/theme/json/set_theme/',
53
- data=json.dumps({'theme': 'dracula-dark'}),
53
+ data=json.dumps({'theme': 'gruvbox-dark'}),
54
54
  content_type='application/json'
55
55
  )
56
56
  response = json_views.set_theme(request)
@@ -63,12 +63,12 @@ class ThemeViewTests(TestCase):
63
63
  self.assertIn('theme', data)
64
64
 
65
65
  data = data['theme']
66
- self.assertEqual(data['family'], 'dracula')
66
+ self.assertEqual(data['family'], 'gruvbox')
67
67
  self.assertEqual(data['mode'], 'dark')
68
68
 
69
69
  cookie_name = get_theme_cookie_name()
70
70
  self.assertIn(cookie_name, response.cookies)
71
- self.assertEqual(response.cookies[cookie_name].value, 'dracula-dark')
71
+ self.assertEqual(response.cookies[cookie_name].value, 'gruvbox-dark')
72
72
 
73
73
  def test_set_theme_missing_theme(self) -> None:
74
74
  request = self.factory.post(
@@ -103,7 +103,7 @@ class ThemeViewIntegrationTests(BaseTestCase):
103
103
  def test_set_theme_with_authenticated_client(self) -> None:
104
104
  response = self.client.post(
105
105
  '/django_spire/theme/json/set_theme/',
106
- data=json.dumps({'theme': 'dracula-dark'}),
106
+ data=json.dumps({'theme': 'gruvbox-dark'}),
107
107
  content_type='application/json'
108
108
  )
109
109