Add account links to footer
Putting them in the navbar is too crowded.
This commit is contained in:
parent
6d60cedc6f
commit
7026aca934
14 changed files with 114 additions and 8 deletions
|
@ -23,6 +23,7 @@ sentry-sdk
|
||||||
wagtail-favicon
|
wagtail-favicon
|
||||||
django-sri
|
django-sri
|
||||||
wagtail-2fa
|
wagtail-2fa
|
||||||
|
django-fontawesome-6
|
||||||
|
|
||||||
# Pinned due to lack of Wagtail 3 support
|
# Pinned due to lack of Wagtail 3 support
|
||||||
git+https://github.com/wagtail/wagtail-autocomplete@03f46a0c256989690d0a43fc21fe0f37f9ede765
|
git+https://github.com/wagtail/wagtail-autocomplete@03f46a0c256989690d0a43fc21fe0f37f9ede765
|
||||||
|
|
|
@ -15,9 +15,10 @@ click==8.1.3 # via rq
|
||||||
coreapi==2.3.3 # via drf-yasg
|
coreapi==2.3.3 # via drf-yasg
|
||||||
coreschema==0.0.4 # via coreapi, drf-yasg
|
coreschema==0.0.4 # via coreapi, drf-yasg
|
||||||
deprecated==1.2.13 # via redis
|
deprecated==1.2.13 # via redis
|
||||||
django==4.0.6 # via -r requirements/base.in, django-filter, django-htmx, django-modelcluster, django-otp, django-permissionedforms, django-plausible, django-redis, django-rq, django-sri, django-taggit, django-treebeard, djangorestframework, drf-yasg, wagtail, wagtail-2fa
|
django==4.0.6 # via -r requirements/base.in, django-filter, django-fontawesome-6, django-htmx, django-modelcluster, django-otp, django-permissionedforms, django-plausible, django-redis, django-rq, django-sri, django-taggit, django-treebeard, djangorestframework, drf-yasg, wagtail, wagtail-2fa
|
||||||
django-environ==0.9.0 # via -r requirements/base.in
|
django-environ==0.9.0 # via -r requirements/base.in
|
||||||
django-filter==21.1 # via wagtail
|
django-filter==21.1 # via wagtail
|
||||||
|
django-fontawesome-6==1.0.0.0 # via -r requirements/base.in
|
||||||
django-htmx==1.12.1 # via -r requirements/base.in
|
django-htmx==1.12.1 # via -r requirements/base.in
|
||||||
django-modelcluster==6.0 # via wagtail
|
django-modelcluster==6.0 # via wagtail
|
||||||
django-otp==1.1.3 # via wagtail-2fa
|
django-otp==1.1.3 # via wagtail-2fa
|
||||||
|
|
|
@ -20,11 +20,12 @@ coreschema==0.0.4 # via -r requirements/base.txt, coreapi, drf-yasg
|
||||||
coverage==6.4.4 # via -r requirements/dev.in
|
coverage==6.4.4 # via -r requirements/dev.in
|
||||||
curlylint==0.13.1 # via -r requirements/dev.in
|
curlylint==0.13.1 # via -r requirements/dev.in
|
||||||
deprecated==1.2.13 # via -r requirements/base.txt, redis
|
deprecated==1.2.13 # via -r requirements/base.txt, redis
|
||||||
django==4.0.6 # via -r requirements/base.txt, django-browser-reload, django-debug-toolbar, django-filter, django-htmx, django-modelcluster, django-otp, django-permissionedforms, django-plausible, django-redis, django-rq, django-sri, django-taggit, django-treebeard, djangorestframework, drf-yasg, wagtail, wagtail-2fa
|
django==4.0.6 # via -r requirements/base.txt, django-browser-reload, django-debug-toolbar, django-filter, django-fontawesome-6, django-htmx, django-modelcluster, django-otp, django-permissionedforms, django-plausible, django-redis, django-rq, django-sri, django-taggit, django-treebeard, djangorestframework, drf-yasg, wagtail, wagtail-2fa
|
||||||
django-browser-reload==1.6.0 # via -r requirements/dev.in
|
django-browser-reload==1.6.0 # via -r requirements/dev.in
|
||||||
django-debug-toolbar==3.5.0 # via -r requirements/dev.in
|
django-debug-toolbar==3.5.0 # via -r requirements/dev.in
|
||||||
django-environ==0.9.0 # via -r requirements/base.txt
|
django-environ==0.9.0 # via -r requirements/base.txt
|
||||||
django-filter==21.1 # via -r requirements/base.txt, wagtail
|
django-filter==21.1 # via -r requirements/base.txt, wagtail
|
||||||
|
django-fontawesome-6==1.0.0.0 # via -r requirements/base.txt
|
||||||
django-htmx==1.12.1 # via -r requirements/base.txt
|
django-htmx==1.12.1 # via -r requirements/base.txt
|
||||||
django-modelcluster==6.0 # via -r requirements/base.txt, wagtail
|
django-modelcluster==6.0 # via -r requirements/base.txt, wagtail
|
||||||
django-otp==1.1.3 # via -r requirements/base.txt, wagtail-2fa
|
django-otp==1.1.3 # via -r requirements/base.txt, wagtail-2fa
|
||||||
|
|
56
website/common/migrations/0022_footersetting.py
Normal file
56
website/common/migrations/0022_footersetting.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# Generated by Django 4.0.6 on 2022-09-02 08:14
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import wagtail.fields
|
||||||
|
import wagtail.snippets.blocks
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("wagtailcore", "0069_log_entry_jsonfield"),
|
||||||
|
("common", "0021_alter_contentpage_body_alter_listingpage_body"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="FooterSetting",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"icons",
|
||||||
|
wagtail.fields.StreamField(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"icon",
|
||||||
|
wagtail.snippets.blocks.SnippetChooserBlock(
|
||||||
|
"contact.OnlineAccount", icon="user"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
use_json_field=None,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"site",
|
||||||
|
models.OneToOneField(
|
||||||
|
editable=False,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to="wagtailcore.site",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Footer",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -12,11 +12,13 @@ from django.utils.functional import cached_property, classproperty
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from wagtail.admin.panels import FieldPanel
|
from wagtail.admin.panels import FieldPanel
|
||||||
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
|
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
|
||||||
|
from wagtail.contrib.settings.models import BaseSetting, register_setting
|
||||||
from wagtail.fields import StreamField
|
from wagtail.fields import StreamField
|
||||||
from wagtail.images import get_image_model_string
|
from wagtail.images import get_image_model_string
|
||||||
from wagtail.images.views.serve import generate_image_url
|
from wagtail.images.views.serve import generate_image_url
|
||||||
from wagtail.models import Page, PageQuerySet
|
from wagtail.models import Page, PageQuerySet
|
||||||
from wagtail.search import index
|
from wagtail.search import index
|
||||||
|
from wagtail.snippets.blocks import SnippetChooserBlock
|
||||||
from wagtail.snippets.models import register_snippet
|
from wagtail.snippets.models import register_snippet
|
||||||
from wagtailmetadata.models import MetadataMixin
|
from wagtailmetadata.models import MetadataMixin
|
||||||
|
|
||||||
|
@ -246,3 +248,15 @@ class ReferralLink(models.Model, index.Indexed):
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
@register_setting(icon="arrow-down")
|
||||||
|
class FooterSetting(BaseSetting):
|
||||||
|
icons = StreamField(
|
||||||
|
[("icon", SnippetChooserBlock("contact.OnlineAccount", icon="user"))]
|
||||||
|
)
|
||||||
|
|
||||||
|
panels = [FieldPanel("icons")]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Footer"
|
||||||
|
|
|
@ -2,7 +2,14 @@
|
||||||
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="content has-text-centered">
|
<div class="content has-text-centered">
|
||||||
<p>
|
{% if online_accounts %}
|
||||||
|
<p class="is-size-3">
|
||||||
|
{% for online_account in online_accounts %}
|
||||||
|
<a href="{{ online_account.url }}" title="{{ online_account.name }}">{{ online_account.icon.as_html }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<p class="is-size-6">
|
||||||
© <a href="{{ homepage_url }}">TheOrangeOne</a> {% now "Y" %}
|
© <a href="{{ homepage_url }}">TheOrangeOne</a> {% now "Y" %}
|
||||||
</p>
|
</p>
|
||||||
<p id="to-top" class="is-size-7">
|
<p id="to-top" class="is-size-7">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
|
|
||||||
|
from website.common.models import FooterSetting
|
||||||
from website.contrib.singleton_page.utils import SingletonPageCache
|
from website.contrib.singleton_page.utils import SingletonPageCache
|
||||||
from website.home.models import HomePage
|
from website.home.models import HomePage
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ register = Library()
|
||||||
@register.inclusion_tag("common/footer.html", takes_context=True)
|
@register.inclusion_tag("common/footer.html", takes_context=True)
|
||||||
def footer(context: dict) -> dict:
|
def footer(context: dict) -> dict:
|
||||||
request = context["request"]
|
request = context["request"]
|
||||||
|
footer_setting = FooterSetting.for_request(request)
|
||||||
return {
|
return {
|
||||||
"homepage_url": SingletonPageCache.get_url(HomePage, request),
|
"homepage_url": SingletonPageCache.get_url(HomePage, request),
|
||||||
|
"online_accounts": [block.value for block in footer_setting.icons],
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ContentPageTestCase(TestCase):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_queries(self) -> None:
|
def test_queries(self) -> None:
|
||||||
with self.assertNumQueries(28):
|
with self.assertNumQueries(32):
|
||||||
self.client.get(self.page.url)
|
self.client.get(self.page.url)
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class ListingPageTestCase(TestCase):
|
||||||
ContentPageFactory(parent=cls.page)
|
ContentPageFactory(parent=cls.page)
|
||||||
|
|
||||||
def test_accessible(self) -> None:
|
def test_accessible(self) -> None:
|
||||||
with self.assertNumQueries(32):
|
with self.assertNumQueries(36):
|
||||||
response = self.client.get(self.page.url)
|
response = self.client.get(self.page.url)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.context["listing_pages"]), 2)
|
self.assertEqual(len(response.context["listing_pages"]), 2)
|
||||||
|
|
|
@ -16,7 +16,7 @@ class Error404PageTestCase(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_queries(self) -> None:
|
def test_queries(self) -> None:
|
||||||
with self.assertNumQueries(16):
|
with self.assertNumQueries(20):
|
||||||
self.client.get(self.url)
|
self.client.get(self.url)
|
||||||
|
|
||||||
|
|
||||||
|
|
19
website/contact/migrations/0007_onlineaccount_icon.py
Normal file
19
website/contact/migrations/0007_onlineaccount_icon.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 4.0.6 on 2022-09-02 07:38
|
||||||
|
|
||||||
|
import fontawesome_6.fields
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("contact", "0006_alter_contactpage_body"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="onlineaccount",
|
||||||
|
name="icon",
|
||||||
|
field=fontawesome_6.fields.IconField(blank=True, max_length=60),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,6 +2,7 @@ from django.db import models
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
|
from fontawesome_6.fields import IconField
|
||||||
from wagtail.admin.panels import FieldPanel
|
from wagtail.admin.panels import FieldPanel
|
||||||
from wagtail.search import index
|
from wagtail.search import index
|
||||||
from wagtail.snippets.models import register_snippet
|
from wagtail.snippets.models import register_snippet
|
||||||
|
@ -15,9 +16,11 @@ class OnlineAccount(models.Model, index.Indexed):
|
||||||
name = models.CharField(max_length=64, unique=True)
|
name = models.CharField(max_length=64, unique=True)
|
||||||
url = models.URLField()
|
url = models.URLField()
|
||||||
username = models.CharField(max_length=64)
|
username = models.CharField(max_length=64)
|
||||||
|
icon = IconField()
|
||||||
|
|
||||||
panels = [
|
panels = [
|
||||||
FieldPanel("name"),
|
FieldPanel("name"),
|
||||||
|
FieldPanel("icon"),
|
||||||
FieldPanel("username"),
|
FieldPanel("username"),
|
||||||
FieldPanel("url"),
|
FieldPanel("url"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="media">
|
<div class="media">
|
||||||
<div class="media-content">
|
<div class="media-content">
|
||||||
<p class="title is-4"><a href="{{ account.url }}">{{ account.name }}</a></p>
|
<p class="title is-4"><a href="{{ account.url }}">{{ account.icon.as_html }} {{ account.name }}</a></p>
|
||||||
<p class="subtitle is-6">{{ account.username }}</p>
|
<p class="subtitle is-6">{{ account.username }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -89,7 +89,7 @@ class SearchPageResultsTestCase(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_too_high_page(self) -> None:
|
def test_too_high_page(self) -> None:
|
||||||
with self.assertNumQueries(46):
|
with self.assertNumQueries(50):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
self.url, {"q": "post", "page": 3}, HTTP_HX_REQUEST="true"
|
self.url, {"q": "post", "page": 3}, HTTP_HX_REQUEST="true"
|
||||||
)
|
)
|
||||||
|
|
|
@ -72,6 +72,7 @@ INSTALLED_APPS = [
|
||||||
"wagtail_2fa",
|
"wagtail_2fa",
|
||||||
"django_otp",
|
"django_otp",
|
||||||
"django_otp.plugins.otp_totp",
|
"django_otp.plugins.otp_totp",
|
||||||
|
"fontawesome_6",
|
||||||
"django.contrib.auth",
|
"django.contrib.auth",
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.contenttypes",
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
|
|
Loading…
Reference in a new issue