Implement footer navigation and social media
This commit is contained in:
parent
8a11ff2c28
commit
b97fed5340
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
.env
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyc
|
||||
0
innovedus_cms/base/__init__.py
Normal file
0
innovedus_cms/base/__init__.py
Normal file
3
innovedus_cms/base/admin.py
Normal file
3
innovedus_cms/base/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
innovedus_cms/base/apps.py
Normal file
6
innovedus_cms/base/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BaseConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'base'
|
||||
55
innovedus_cms/base/migrations/0001_initial.py
Normal file
55
innovedus_cms/base/migrations/0001_initial.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-15 03:30
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
import wagtail.fields
|
||||
import wagtail.models.preview
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0095_groupsitepermission'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NavigationSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('linkedin_url', models.URLField(blank=True, verbose_name='LinkedIn URL')),
|
||||
('github_url', models.URLField(blank=True, verbose_name='GitHub URL')),
|
||||
('mastodon_url', models.URLField(blank=True, verbose_name='Mastodon URL')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FooterText',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('translation_key', models.UUIDField(default=uuid.uuid4, editable=False)),
|
||||
('live', models.BooleanField(default=True, editable=False, verbose_name='live')),
|
||||
('has_unpublished_changes', models.BooleanField(default=False, editable=False, verbose_name='has unpublished changes')),
|
||||
('first_published_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='first published at')),
|
||||
('last_published_at', models.DateTimeField(editable=False, null=True, verbose_name='last published at')),
|
||||
('go_live_at', models.DateTimeField(blank=True, null=True, verbose_name='go live date/time')),
|
||||
('expire_at', models.DateTimeField(blank=True, null=True, verbose_name='expiry date/time')),
|
||||
('expired', models.BooleanField(default=False, editable=False, verbose_name='expired')),
|
||||
('body', wagtail.fields.RichTextField()),
|
||||
('latest_revision', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.revision', verbose_name='latest revision')),
|
||||
('live_revision', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.revision', verbose_name='live revision')),
|
||||
('locale', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Footer Text',
|
||||
'abstract': False,
|
||||
'unique_together': {('translation_key', 'locale')},
|
||||
},
|
||||
bases=(wagtail.models.preview.PreviewableMixin, models.Model),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,36 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-15 06:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='navigationsettings',
|
||||
name='github_url',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='navigationsettings',
|
||||
name='mastodon_url',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='navigationsettings',
|
||||
name='facebook_url',
|
||||
field=models.URLField(blank=True, verbose_name='Facebook URL'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='navigationsettings',
|
||||
name='instagram_url',
|
||||
field=models.URLField(blank=True, verbose_name='Instagram URL'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='navigationsettings',
|
||||
name='thread_url',
|
||||
field=models.URLField(blank=True, verbose_name='Thread URL'),
|
||||
),
|
||||
]
|
||||
24
innovedus_cms/base/migrations/0003_socialmediasettings.py
Normal file
24
innovedus_cms/base/migrations/0003_socialmediasettings.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-15 06:48
|
||||
|
||||
import wagtail.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0002_remove_navigationsettings_github_url_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SocialMediaSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('links', wagtail.fields.StreamField([('link', 2)], block_lookup={0: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('twitter', 'Twitter'), ('instagram', 'Instagram'), ('linkedin', 'LinkedIn'), ('youtube', 'YouTube')]}), 1: ('wagtail.blocks.URLBlock', (), {}), 2: ('wagtail.blocks.StructBlock', [[('platform', 0), ('url', 1)]], {})})),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,44 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-15 08:49
|
||||
|
||||
import wagtail.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0003_socialmediasettings'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='navigationsettings',
|
||||
options={'verbose_name': 'Footer Navigation'},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='navigationsettings',
|
||||
name='facebook_url',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='navigationsettings',
|
||||
name='instagram_url',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='navigationsettings',
|
||||
name='linkedin_url',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='navigationsettings',
|
||||
name='thread_url',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='navigationsettings',
|
||||
name='footer_links',
|
||||
field=wagtail.fields.StreamField([('section', 5)], blank=True, block_lookup={0: ('wagtail.blocks.CharBlock', (), {'required': False}), 1: ('wagtail.blocks.CharBlock', (), {}), 2: ('wagtail.blocks.URLBlock', (), {}), 3: ('wagtail.blocks.StructBlock', [[('label', 1), ('url', 2)]], {}), 4: ('wagtail.blocks.ListBlock', (3,), {}), 5: ('wagtail.blocks.StructBlock', [[('title', 0), ('links', 4)]], {})}, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='socialmediasettings',
|
||||
name='links',
|
||||
field=wagtail.fields.StreamField([('link', 2)], block_lookup={0: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('facebook', 'Facebook'), ('twitter', 'Twitter'), ('instagram', 'Instagram'), ('thread', 'Thread'), ('linkedin', 'LinkedIn'), ('youtube', 'YouTube')]}), 1: ('wagtail.blocks.URLBlock', (), {}), 2: ('wagtail.blocks.StructBlock', [[('platform', 0), ('url', 1)]], {})}),
|
||||
),
|
||||
]
|
||||
0
innovedus_cms/base/migrations/__init__.py
Normal file
0
innovedus_cms/base/migrations/__init__.py
Normal file
100
innovedus_cms/base/models.py
Normal file
100
innovedus_cms/base/models.py
Normal file
@ -0,0 +1,100 @@
|
||||
from django.db import models
|
||||
from wagtail.admin.panels import (
|
||||
FieldPanel,
|
||||
MultiFieldPanel,
|
||||
|
||||
# import PublishingPanel:
|
||||
PublishingPanel,
|
||||
)
|
||||
|
||||
# import RichTextField:
|
||||
from wagtail.fields import RichTextField
|
||||
|
||||
# import DraftStateMixin, PreviewableMixin, RevisionMixin, TranslatableMixin:
|
||||
from wagtail.models import (
|
||||
DraftStateMixin,
|
||||
PreviewableMixin,
|
||||
RevisionMixin,
|
||||
TranslatableMixin,
|
||||
)
|
||||
|
||||
from wagtail.contrib.settings.models import (
|
||||
BaseGenericSetting,
|
||||
register_setting,
|
||||
)
|
||||
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from wagtail.fields import StreamField
|
||||
from wagtail import blocks
|
||||
|
||||
@register_setting
|
||||
class NavigationSettings(BaseGenericSetting):
|
||||
footer_links = StreamField([
|
||||
("section", blocks.StructBlock([
|
||||
("title", blocks.CharBlock(required=False)),
|
||||
("links", blocks.ListBlock(blocks.StructBlock([
|
||||
("label", blocks.CharBlock()),
|
||||
("url", blocks.URLBlock())
|
||||
]))),
|
||||
]))
|
||||
], use_json_field=True, blank=True, null=True)
|
||||
|
||||
panels = [
|
||||
FieldPanel("footer_links"),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Footer Navigation"
|
||||
|
||||
class SocialLinkBlock(blocks.StructBlock):
|
||||
SOCIAL_MEDIA_CHOICES = [
|
||||
("facebook", "Facebook"),
|
||||
("twitter", "Twitter"),
|
||||
("instagram", "Instagram"),
|
||||
("thread", "Thread"),
|
||||
("linkedin", "LinkedIn"),
|
||||
("youtube", "YouTube"),
|
||||
]
|
||||
|
||||
platform = blocks.ChoiceBlock(choices=SOCIAL_MEDIA_CHOICES)
|
||||
url = blocks.URLBlock()
|
||||
|
||||
class Meta:
|
||||
icon = "link"
|
||||
label = "Social Link"
|
||||
|
||||
@register_setting
|
||||
class SocialMediaSettings(BaseGenericSetting):
|
||||
links = StreamField([
|
||||
("link", SocialLinkBlock()),
|
||||
], use_json_field=True)
|
||||
|
||||
panels = [FieldPanel("links")]
|
||||
|
||||
@register_snippet
|
||||
class FooterText(
|
||||
DraftStateMixin,
|
||||
RevisionMixin,
|
||||
PreviewableMixin,
|
||||
TranslatableMixin,
|
||||
models.Model,
|
||||
):
|
||||
|
||||
body = RichTextField()
|
||||
|
||||
panels = [
|
||||
FieldPanel("body"),
|
||||
PublishingPanel(),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return "Footer text"
|
||||
|
||||
def get_preview_template(self, request, mode_name):
|
||||
return "base.html"
|
||||
|
||||
def get_preview_context(self, request, mode_name):
|
||||
return {"footer_text": self.body}
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name_plural = "Footer Text"
|
||||
@ -0,0 +1,5 @@
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
<div>
|
||||
{{ footer_text|richtext }}
|
||||
</div>
|
||||
0
innovedus_cms/base/templatetags/__init__.py
Normal file
0
innovedus_cms/base/templatetags/__init__.py
Normal file
18
innovedus_cms/base/templatetags/navigation_tags.py
Normal file
18
innovedus_cms/base/templatetags/navigation_tags.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django import template
|
||||
|
||||
from base.models import FooterText
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.inclusion_tag("base/includes/footer_text.html", takes_context=True)
|
||||
def get_footer_text(context):
|
||||
footer_text = context.get("footer_text", "")
|
||||
|
||||
if not footer_text:
|
||||
instance = FooterText.objects.filter(live=True).first()
|
||||
footer_text = instance.body if instance else ""
|
||||
|
||||
return {
|
||||
"footer_text": footer_text,
|
||||
}
|
||||
3
innovedus_cms/base/tests.py
Normal file
3
innovedus_cms/base/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
3
innovedus_cms/base/views.py
Normal file
3
innovedus_cms/base/views.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
@ -3,6 +3,10 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# from dotenv import load_dotenv
|
||||
|
||||
# env_file = os.environ.get("ENV_FILE", "../.env")
|
||||
# load_dotenv(env_file)
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
|
||||
@ -28,6 +28,7 @@ INSTALLED_APPS = [
|
||||
"search",
|
||||
"wagtail.contrib.forms",
|
||||
"wagtail.contrib.redirects",
|
||||
"wagtail.contrib.settings",
|
||||
"wagtail.embeds",
|
||||
"wagtail.sites",
|
||||
"wagtail.users",
|
||||
@ -46,6 +47,7 @@ INSTALLED_APPS = [
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"base",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -74,6 +76,7 @@ TEMPLATES = [
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"wagtail.contrib.settings.context_processors.settings",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@ -36,6 +36,8 @@
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
{% include "includes/footer.html" %}
|
||||
|
||||
{# Global javascript #}
|
||||
<script type="text/javascript" src="{% static 'js/mysite.js' %}"></script>
|
||||
|
||||
|
||||
32
innovedus_cms/mysite/templates/includes/footer.html
Normal file
32
innovedus_cms/mysite/templates/includes/footer.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% load navigation_tags %}
|
||||
|
||||
<footer>
|
||||
{% if settings.base.NavigationSettings.footer_links %}
|
||||
<div class="footer-sections">
|
||||
{% for section in settings.base.NavigationSettings.footer_links %}
|
||||
<div class="footer-section">
|
||||
{% if section.value.title %}
|
||||
<h3>{{ section.value.title }}</h3>
|
||||
{% endif %}
|
||||
<ul>
|
||||
{% for link in section.value.links %}
|
||||
<li><a href="{{ link.url }}" target="_blank">{{ link.label }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% with social_links=settings.base.SocialMediaSettings.links %}
|
||||
{% if social_links %}
|
||||
<p>Follow us
|
||||
{% for item in social_links %}
|
||||
<a href="{{ item.value.url }}" target="_blank" alt="{{ item.value.platform }}">{{ item.value.platform }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% get_footer_text %}
|
||||
</footer>
|
||||
Loading…
x
Reference in New Issue
Block a user