Browse Source

transmitters original texts and opinions better appearance in admin panel

master
Mohsen Taba 1 month ago
parent
commit
f842e68a8c
  1. 129
      apps/account/templates/account/json_editor_field.html
  2. 3
      apps/hadis/admin/hadis.py
  3. 1
      apps/hadis/admin/reference.py
  4. 149
      apps/hadis/admin/transmitter.py

129
apps/account/templates/account/json_editor_field.html

@ -1,8 +1,7 @@
{% load i18n %}
<div class="json-editor-container">
<textarea style="display: none" name="{{ widget.name }}" id="{{ widget.attrs.id }}"
{% include "django/forms/widgets/attrs.html" %}
>{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
<textarea style="display: none" name="{{ widget.name }}" id="{{ widget.attrs.id }}" {%
include "django/forms/widgets/attrs.html" %}>{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
<div class="json-view-editor" id='date-view-editor-{{ widget.attrs.id }}'></div>
</div>
@ -429,24 +428,28 @@
align-items: center !important;
justify-content: center !important;
gap: 0.375rem !important;
background-color: rgb(37, 208, 118) !important; /* Unfold primary-500 */
background-color: rgb(37, 208, 118) !important;
/* Unfold primary-500 */
color: white !important;
border: none !important;
border-radius: 0.375rem !important;
padding: 0.5rem 0.875rem !important; /* Smaller padding */
padding: 0.5rem 0.875rem !important;
/* Smaller padding */
font-weight: 500 !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
margin: 0 0.25rem !important;
font-size: 0.8125rem !important; /* Smaller font */
font-size: 0.8125rem !important;
/* Smaller font */
line-height: 1.4 !important;
text-transform: none !important;
letter-spacing: 0.01em !important;
}
.json-editor-btn-modern:hover {
background-color: rgb(29, 166, 94) !important; /* Unfold primary-600 */
background-color: rgb(29, 166, 94) !important;
/* Unfold primary-600 */
transform: translateY(-1px) !important;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08) !important;
}
@ -457,7 +460,8 @@
}
/* Button sections styling */
.json-editor-btngroup, .json-editor-btn-bar {
.json-editor-btngroup,
.json-editor-btn-bar {
display: flex !important;
flex-wrap: wrap !important;
gap: 0.5rem !important;
@ -480,23 +484,29 @@
/* Add button styling */
.json-editor-btn-add {
background-color: rgb(37, 208, 118) !important; /* Unfold primary-500 */
padding: 0.625rem 1rem !important; /* Smaller padding */
font-size: 0.875rem !important; /* Smaller font */
background-color: rgb(37, 208, 118) !important;
/* Unfold primary-500 */
padding: 0.625rem 1rem !important;
/* Smaller padding */
font-size: 0.875rem !important;
/* Smaller font */
font-weight: 600 !important;
letter-spacing: 0.01em !important;
border-radius: 0.375rem !important;
width: auto !important; /* Not full width */
width: auto !important;
/* Not full width */
margin-bottom: 0.75rem !important;
}
.json-editor-btn-add:hover {
background-color: rgb(29, 166, 94) !important; /* Unfold primary-600 */
background-color: rgb(29, 166, 94) !important;
/* Unfold primary-600 */
}
/* Modern HTML5-like error styling */
.je-error-container {
display: none !important; /* Hide the default error container */
display: none !important;
/* Hide the default error container */
}
/* Style for invalid inputs */
@ -577,11 +587,13 @@
/* Delete button styling */
.json-editor-btn-delete {
background-color: rgb(1, 53, 59) !important; /* Unfold secondary-500 */
background-color: rgb(1, 53, 59) !important;
/* Unfold secondary-500 */
}
.json-editor-btn-delete:hover {
background-color: rgb(1, 43, 48) !important; /* Unfold secondary-600 */
background-color: rgb(1, 43, 48) !important;
/* Unfold secondary-600 */
}
/* Hide Delete Last buttons */
@ -590,29 +602,36 @@
}
/* Move up/down buttons */
.json-editor-btntype-moveup, .json-editor-btntype-movedown {
.json-editor-btntype-moveup,
.json-editor-btntype-movedown {
background-color: rgba(1, 53, 59, 0.8) !important;
}
.json-editor-btntype-moveup:hover, .json-editor-btntype-movedown:hover {
.json-editor-btntype-moveup:hover,
.json-editor-btntype-movedown:hover {
background-color: rgb(1, 53, 59) !important;
}
/* Button sections styling */
.json-editor-btngroup, .json-editor-btn-bar {
.json-editor-btngroup,
.json-editor-btn-bar {
display: flex !important;
flex-wrap: wrap !important;
gap: 0.375rem !important;
margin-top: 1rem !important;
padding: 0.625rem !important;
background-color: rgba(1, 53, 59, 0.03) !important; /* More subtle background */
border: 1px solid rgba(1, 53, 59, 0.08) !important; /* Subtle border */
background-color: rgba(1, 53, 59, 0.03) !important;
/* More subtle background */
border: 1px solid rgba(1, 53, 59, 0.08) !important;
/* Subtle border */
border-radius: 0.5rem !important;
visibility: visible !important;
width: 100% !important;
justify-content: flex-end !important;
order: 999 !important; /* Ensure it appears at the bottom */
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02) !important; /* Subtle shadow */
order: 999 !important;
/* Ensure it appears at the bottom */
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02) !important;
/* Subtle shadow */
}
/* Modern button group styling */
@ -649,7 +668,8 @@
}
/* Form labels */
label, .je-label {
label,
.je-label {
font-size: 0.875rem !important;
font-weight: 500 !important;
color: rgb(1, 53, 59) !important;
@ -675,7 +695,8 @@
}
/* Labels */
label, .je-label {
label,
.je-label {
display: block !important;
margin-bottom: 0.5rem !important;
font-weight: 500 !important;
@ -684,7 +705,8 @@
}
/* Form groups */
.form-group, .je-object__container {
.form-group,
.je-object__container {
margin-bottom: 1.5rem !important;
width: 100% !important;
}
@ -714,31 +736,39 @@
/* Dark mode support - Using Unfold color scheme */
@media (prefers-color-scheme: dark) {
.json-editor-container {
background-color: rgb(1, 43, 48) !important; /* Unfold secondary-600 */
background-color: rgb(1, 43, 48) !important;
/* Unfold secondary-600 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.json-view-editor {
background-color: rgb(1, 43, 48) !important; /* Unfold secondary-600 */
background-color: rgb(1, 43, 48) !important;
/* Unfold secondary-600 */
}
.table-responsive {
border-color: rgb(1, 36, 40) !important; /* Unfold secondary-700 */
background-color: rgb(1, 43, 48) !important; /* Unfold secondary-600 */
border-color: rgb(1, 36, 40) !important;
/* Unfold secondary-700 */
background-color: rgb(1, 43, 48) !important;
/* Unfold secondary-600 */
}
.modern-table-header {
background-color: rgb(1, 30, 34) !important; /* Unfold secondary-800 */
background-color: rgb(1, 30, 34) !important;
/* Unfold secondary-800 */
color: white !important;
border-bottom-color: rgb(0, 26, 29) !important; /* Unfold secondary-900 */
border-bottom-color: rgb(0, 26, 29) !important;
/* Unfold secondary-900 */
}
.modern-table-row {
border-bottom-color: rgb(1, 30, 34) !important; /* Unfold secondary-800 */
border-bottom-color: rgb(1, 30, 34) !important;
/* Unfold secondary-800 */
}
.modern-table-row:hover {
background-color: rgb(1, 36, 40) !important; /* Unfold secondary-700 */
background-color: rgb(1, 36, 40) !important;
/* Unfold secondary-700 */
}
.modern-table-row td {
@ -746,24 +776,31 @@
}
.modern-form-control {
background-color: rgb(1, 36, 40) !important; /* Unfold secondary-700 */
border-color: rgb(1, 30, 34) !important; /* Unfold secondary-800 */
background-color: rgb(1, 36, 40) !important;
/* Unfold secondary-700 */
border-color: rgb(1, 30, 34) !important;
/* Unfold secondary-800 */
color: white !important;
}
label, .je-label {
label,
.je-label {
color: white !important;
}
/* Button sections in dark mode */
.json-editor-btngroup, .json-editor-btn-bar {
background-color: rgba(1, 30, 34, 0.25) !important; /* More subtle dark background */
border: 1px solid rgba(37, 208, 118, 0.1) !important; /* Subtle primary color border */
.json-editor-btngroup,
.json-editor-btn-bar {
background-color: rgba(1, 30, 34, 0.25) !important;
/* More subtle dark background */
border: 1px solid rgba(37, 208, 118, 0.1) !important;
/* Subtle primary color border */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
}
.modern-form-control:focus {
border-color: rgb(37, 208, 118) !important; /* Unfold primary-500 */
border-color: rgb(37, 208, 118) !important;
/* Unfold primary-500 */
box-shadow: 0 0 0 3px rgba(37, 208, 118, 0.2) !important;
}
@ -772,12 +809,14 @@
.je-error+select,
.je-error+textarea,
.has-error .modern-form-control {
border-color: rgb(252, 165, 165) !important; /* Lighter red for dark mode */
border-color: rgb(252, 165, 165) !important;
/* Lighter red for dark mode */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23fca5a5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");
}
.je-error::after {
background-color: rgb(185, 28, 28) !important; /* Darker red background for tooltip */
background-color: rgb(185, 28, 28) !important;
/* Darker red background for tooltip */
color: white !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.25) !important;
}
@ -788,7 +827,8 @@
/* Card styling in dark mode */
.modern-card {
background-color: rgb(1, 43, 48) !important; /* Unfold secondary-600 */
background-color: rgb(1, 43, 48) !important;
/* Unfold secondary-600 */
}
/* Error messages in dark mode */
@ -797,4 +837,3 @@
}
}
</style>

3
apps/hadis/admin/hadis.py

@ -589,8 +589,9 @@ class ReferenceImageInline(TabularInline):
class HadisReferenceInline(TabularInline):
"""Inline for HadisReference in Hadis admin"""
model = HadisReference
form = HadisReferenceAdminForm
extra = 0
fields = ('book_reference',)
fields = ('book_reference', 'description')
readonly_fields = ('created_at',)

1
apps/hadis/admin/reference.py

@ -415,6 +415,7 @@ class BookAttributeInline(TabularInline):
Inline for managing Book Attributes (Key-Value pairs) inside BookReference.
"""
model = BookAttribute
form = BookAttributeAdminForm
extra = 0
fields = ('title', 'value')
readonly_fields = ('created_at',)

149
apps/hadis/admin/transmitter.py

@ -20,18 +20,7 @@ class HadisTransmitterInline(TabularInline):
fields = ('hadis', 'order')
class TransmitterOpinionInline(TabularInline):
"""Inline for TransmitterOpinion in Transmitters admin"""
model = TransmitterOpinion
extra = 0
fields = ('scholar_name', 'status')
class TransmitterOriginalTextInline(TabularInline):
"""Inline for TransmitterOriginalText in Transmitters admin"""
model = TransmitterOriginalText
extra = 0
fields = ('title', 'slug')
# (TransmitterOpinionInline and TransmitterOriginalTextInline moved after their forms)
# Custom Forms for JSON Fields
@ -123,63 +112,7 @@ class TransmittersAdminForm(forms.ModelForm):
})
class TransmittersAdmin(ModelAdmin):
"""Admin for Transmitters model"""
form = TransmittersAdminForm
list_display = ('display_header', 'birth_year_hijri', 'death_year_hijri')
list_filter = ('birth_year_hijri', 'death_year_hijri')
search_fields = ('full_name', 'description')
readonly_fields = ('created_at', 'updated_at')
inlines = [HadisTransmitterInline, TransmitterOpinionInline, TransmitterOriginalTextInline]
fieldsets = (
(None, {
'fields': ('full_name', 'birth_year_hijri', 'death_year_hijri','known_as','nickname')
}),
(_('Additional Information'), {
'fields': ('description','origin','lived_in','died_in','kunya'),
# 'classes': ('collapse',)
}),
(_('Timestamps'), {
'fields': ('created_at', 'updated_at'),
# 'classes': ('collapse',)
}),
)
@display(description=_('Full Name'), ordering='full_name')
def get_full_name_display(self, obj):
"""
Parses the JSON full_name and returns the first item's text.
"""
if obj.full_name and isinstance(obj.full_name, list) and len(obj.full_name) > 0:
# Safely get the first item
first_item = obj.full_name[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return '-'
@display(description=_("Transmitter"), header=True)
def display_header(self, obj):
return self.get_full_name_display(obj),
class HadisTransmitterAdmin(ModelAdmin):
"""Admin for HadisTransmitter model"""
list_display = ('hadis', 'transmitter', 'order', 'created_at')
list_filter = ( 'created_at',)
search_fields = ('hadis__title', 'transmitter__full_name')
readonly_fields = ('created_at',)
ordering = ('hadis', 'order')
fieldsets = (
(None, {
'fields': ('hadis', 'transmitter', 'order')
}),
(_('Timestamps'), {
'fields': ('created_at',),
'classes': ('collapse',)
}),
)
# (Admins moved down to avoid NameError)
# Custom Forms for JSON Fields
@ -513,6 +446,84 @@ class TransmitterOriginalTextAdminForm(forms.ModelForm):
})
class TransmitterOpinionInline(TabularInline):
"""Inline for TransmitterOpinion in Transmitters admin"""
model = TransmitterOpinion
form = TransmitterOpinionAdminForm
extra = 0
fields = ('scholar_name', 'opinion_text', 'status')
def has_add_permission(self, request, obj=None):
return False
class TransmitterOriginalTextInline(TabularInline):
"""Inline for TransmitterOriginalText in Transmitters admin"""
model = TransmitterOriginalText
form = TransmitterOriginalTextAdminForm
extra = 0
fields = ('title', 'text', 'translation', 'slug')
def has_add_permission(self, request, obj=None):
return False
class TransmittersAdmin(ModelAdmin):
"""Admin for Transmitters model"""
form = TransmittersAdminForm
list_display = ('display_header', 'birth_year_hijri', 'death_year_hijri')
list_filter = ('birth_year_hijri', 'death_year_hijri')
search_fields = ('full_name', 'description')
readonly_fields = ('created_at', 'updated_at')
inlines = [HadisTransmitterInline, TransmitterOpinionInline, TransmitterOriginalTextInline]
fieldsets = (
(None, {
'fields': ('full_name', 'birth_year_hijri', 'death_year_hijri','known_as','nickname')
}),
(_('Additional Information'), {
'fields': ('description','origin','lived_in','died_in','kunya'),
# 'classes': ('collapse',)
}),
(_('Timestamps'), {
'fields': ('created_at', 'updated_at'),
# 'classes': ('collapse',)
}),
)
@display(description=_('Full Name'), ordering='full_name')
def get_full_name_display(self, obj):
"""
Parses the JSON full_name and returns the first item's text.
"""
if obj.full_name and isinstance(obj.full_name, list) and len(obj.full_name) > 0:
# Safely get the first item
first_item = obj.full_name[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return '-'
@display(description=_("Transmitter"), header=True)
def display_header(self, obj):
return self.get_full_name_display(obj),
class HadisTransmitterAdmin(ModelAdmin):
"""Admin for HadisTransmitter model"""
list_display = ('hadis', 'transmitter', 'order', 'created_at')
list_filter = ( 'created_at',)
search_fields = ('hadis__title', 'transmitter__full_name')
readonly_fields = ('created_at',)
ordering = ('hadis', 'order')
fieldsets = (
(None, {
'fields': ('hadis', 'transmitter', 'order')
}),
(_('Timestamps'), {
'fields': ('created_at',),
'classes': ('collapse',)
}),
)
# Main Admin Classes
class NarratorLayerAdmin(ModelAdmin):
"""Admin for NarratorLayer model"""

Loading…
Cancel
Save