feat: rebuild site content management
Replace legacy FAQ, downloads, and release flows with project and blog publishing. Add configurable branding and theme fields plus clean-start Compose seeding support.
This commit is contained in:
+64
-2
@@ -1,8 +1,12 @@
|
||||
from django.core.validators import FileExtensionValidator
|
||||
from django.core.validators import FileExtensionValidator, RegexValidator
|
||||
from django.db import models
|
||||
|
||||
|
||||
class SiteBranding(models.Model):
|
||||
hex_color_validator = RegexValidator(
|
||||
regex=r"^#[0-9A-Fa-f]{6}$",
|
||||
message="Enter a six-digit hex colour such as #4f8ef7.",
|
||||
)
|
||||
OBJECT_FIT_COVER = "cover"
|
||||
OBJECT_FIT_CONTAIN = "contain"
|
||||
OBJECT_FIT_CHOICES = [
|
||||
@@ -10,6 +14,23 @@ class SiteBranding(models.Model):
|
||||
(OBJECT_FIT_CONTAIN, "Contain (fit inside square)"),
|
||||
]
|
||||
|
||||
site_name = models.CharField(max_length=120, default="Communication to Care")
|
||||
short_name = models.CharField(
|
||||
max_length=60,
|
||||
default="com2care",
|
||||
help_text="Compact name used in the navigation bar.",
|
||||
)
|
||||
tagline = models.CharField(
|
||||
max_length=300,
|
||||
default="Turning complex medical-imaging evidence into clearer, reproducible research conversations.",
|
||||
blank=True,
|
||||
)
|
||||
meta_description = models.CharField(
|
||||
max_length=300,
|
||||
default="Communication to Care — Advanced Medical Imaging and Radiomics Solutions",
|
||||
blank=True,
|
||||
)
|
||||
|
||||
icon = models.ImageField(
|
||||
upload_to="branding/",
|
||||
blank=True,
|
||||
@@ -77,13 +98,34 @@ class SiteBranding(models.Model):
|
||||
choices=OBJECT_FIT_CHOICES,
|
||||
default=OBJECT_FIT_COVER,
|
||||
)
|
||||
background_color = models.CharField(
|
||||
max_length=7, default="#070713", validators=[hex_color_validator]
|
||||
)
|
||||
surface_color = models.CharField(
|
||||
max_length=7, default="#10102a", validators=[hex_color_validator]
|
||||
)
|
||||
primary_color = models.CharField(
|
||||
max_length=7, default="#4f8ef7", validators=[hex_color_validator]
|
||||
)
|
||||
secondary_color = models.CharField(
|
||||
max_length=7, default="#a78bfa", validators=[hex_color_validator]
|
||||
)
|
||||
accent_color = models.CharField(
|
||||
max_length=7, default="#22d3ee", validators=[hex_color_validator]
|
||||
)
|
||||
text_color = models.CharField(
|
||||
max_length=7, default="#eef2ff", validators=[hex_color_validator]
|
||||
)
|
||||
muted_text_color = models.CharField(
|
||||
max_length=7, default="#a6abc2", validators=[hex_color_validator]
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Site Branding"
|
||||
verbose_name_plural = "Site Branding"
|
||||
|
||||
def __str__(self):
|
||||
return "Site Branding"
|
||||
return self.site_name
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
@@ -108,6 +150,26 @@ class SiteBranding(models.Model):
|
||||
def footer_icon_style(self):
|
||||
return self.icon_style(self.footer_icon_size)
|
||||
|
||||
@property
|
||||
def theme_style(self):
|
||||
return ";".join(
|
||||
(
|
||||
f"--bg-primary:{self.background_color}",
|
||||
f"--bg-secondary:{self.background_color}",
|
||||
f"--bg-surface:{self.surface_color}",
|
||||
f"--accent-blue:{self.primary_color}",
|
||||
f"--accent-blue-light:{self.primary_color}",
|
||||
f"--accent-purple:{self.secondary_color}",
|
||||
f"--accent-cyan:{self.accent_color}",
|
||||
f"--text-primary:{self.text_color}",
|
||||
f"--text-secondary:{self.muted_text_color}",
|
||||
f"--text-muted:{self.muted_text_color}",
|
||||
f"--text-link:{self.primary_color}",
|
||||
f"--gradient-brand:linear-gradient(135deg,{self.primary_color} 0%,{self.secondary_color} 100%)",
|
||||
f"--gradient-text:linear-gradient(135deg,{self.primary_color} 0%,{self.secondary_color} 50%,{self.accent_color} 100%)",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class SiteContact(models.Model):
|
||||
support_email = models.EmailField(
|
||||
|
||||
Reference in New Issue
Block a user