From 1274988c5fed1d8f23b244fba7408d6883d138cf Mon Sep 17 00:00:00 2001 From: luxagraf Date: Fri, 15 Mar 2019 21:57:12 -0600 Subject: added related items complete with template and styles --- app/jrnl/admin.py | 17 +++++- .../0001_squashed_0019_remove_entry_thumbnail.py | 5 ++ app/jrnl/migrations/0036_enjoyitem.py | 23 +++++++ app/jrnl/migrations/0037_enjoyitem_entry.py | 20 ++++++ app/jrnl/migrations/0038_remove_enjoyitem_entry.py | 17 ++++++ app/jrnl/migrations/0039_enjoyitem_order.py | 18 ++++++ app/jrnl/migrations/0040_auto_20190315_1906.py | 20 ++++++ app/jrnl/migrations/0041_auto_20190315_2240.py | 28 +++++++++ app/jrnl/models.py | 11 ++++ app/jrnl/views.py | 6 ++ app/sightings/models.py | 7 ++- design/sass/_details.scss | 71 ++++++++++++++++++++++ design/sass/_footer.scss | 10 ++- design/sass/_mixins.scss | 2 +- design/sass/_typography.scss | 10 +++ design/sass/screenv9.scss | 3 +- design/templates/archives/homepage-light.html | 2 +- design/templates/base.html | 4 +- design/templates/jrnl/entry_detail.html | 26 ++++++++ design/templates/lib/img_archive.html | 2 +- 20 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 app/jrnl/migrations/0036_enjoyitem.py create mode 100644 app/jrnl/migrations/0037_enjoyitem_entry.py create mode 100644 app/jrnl/migrations/0038_remove_enjoyitem_entry.py create mode 100644 app/jrnl/migrations/0039_enjoyitem_order.py create mode 100644 app/jrnl/migrations/0040_auto_20190315_1906.py create mode 100644 app/jrnl/migrations/0041_auto_20190315_2240.py create mode 100644 design/sass/_typography.scss diff --git a/app/jrnl/admin.py b/app/jrnl/admin.py index 3c35272..d800f34 100644 --- a/app/jrnl/admin.py +++ b/app/jrnl/admin.py @@ -1,19 +1,31 @@ from django.contrib import admin from django import forms from django.contrib.gis.admin import OSMGeoAdmin +from django.contrib.contenttypes.admin import GenericStackedInline from utils.widgets import AdminImageWidget, LGEntryForm -from .models import Entry, HomepageCurrator, Home +from .models import Entry, HomepageCurrator, Home, RelatedPost from photos.forms import GalleryForm from photos.models import LuxImage from utils.util import get_latlon +@admin.register(RelatedPost) +class RelatedPostAdmin(admin.ModelAdmin): + pass + + @admin.register(Entry) class EntryAdmin(OSMGeoAdmin): form = LGEntryForm + def get_queryset(self, request): + test_model_qs = super(EntryAdmin, self).get_queryset(request) + test_model_qs = test_model_qs.prefetch_related('related').prefetch_related('books') + + return test_model_qs + def render_change_form(self, request, context, *args, **kwargs): #context['adminform'].form.fields['featured_image'].queryset = LuxImage.objects.all()[:200] return super(EntryAdmin, self).render_change_form(request, context, *args, **kwargs) @@ -32,7 +44,7 @@ class EntryAdmin(OSMGeoAdmin): search_fields = ['title', 'body_markdown'] prepopulated_fields = {"slug": ('title',)} list_filter = ('pub_date', 'enable_comments', 'status', 'location__state__country__lux_region') - filter_horizontal = ('field_notes', 'books') + filter_horizontal = ('field_notes', 'books', 'related') fieldsets = ( ('Entry', { 'fields': ( @@ -63,6 +75,7 @@ class EntryAdmin(OSMGeoAdmin): 'fields': ( 'field_notes', 'books', + 'related', ), 'classes': ( 'collapse', diff --git a/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py b/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py index 4b1dea3..7b1b247 100644 --- a/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py +++ b/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py @@ -68,6 +68,11 @@ class Migration(migrations.Migration): name='image', field=models.FileField(blank=True, help_text='should be 520 by 290', null=True, upload_to=jrnl.models.get_upload_path), ), + migrations.AddField( + model_name='entry', + name='field_notes', + field=models.ManyToManyField(blank=True, to='fieldnotes.FieldNote'), + ), migrations.AddField( model_name='entry', name='books', diff --git a/app/jrnl/migrations/0036_enjoyitem.py b/app/jrnl/migrations/0036_enjoyitem.py new file mode 100644 index 0000000..aaa8596 --- /dev/null +++ b/app/jrnl/migrations/0036_enjoyitem.py @@ -0,0 +1,23 @@ +# Generated by Django 2.1.7 on 2019-03-14 23:42 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('jrnl', '0035_auto_20190303_1610'), + ] + + operations = [ + migrations.CreateModel( + name='EnjoyItem', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('object_id', models.PositiveIntegerField()), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), + ], + ), + ] diff --git a/app/jrnl/migrations/0037_enjoyitem_entry.py b/app/jrnl/migrations/0037_enjoyitem_entry.py new file mode 100644 index 0000000..733f94c --- /dev/null +++ b/app/jrnl/migrations/0037_enjoyitem_entry.py @@ -0,0 +1,20 @@ +# Generated by Django 2.1.7 on 2019-03-15 00:13 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('jrnl', '0036_enjoyitem'), + ] + + operations = [ + migrations.AddField( + model_name='enjoyitem', + name='entry', + field=models.ForeignKey(default='', on_delete=django.db.models.deletion.CASCADE, to='jrnl.Entry'), + preserve_default=False, + ), + ] diff --git a/app/jrnl/migrations/0038_remove_enjoyitem_entry.py b/app/jrnl/migrations/0038_remove_enjoyitem_entry.py new file mode 100644 index 0000000..0eec153 --- /dev/null +++ b/app/jrnl/migrations/0038_remove_enjoyitem_entry.py @@ -0,0 +1,17 @@ +# Generated by Django 2.1.7 on 2019-03-15 00:20 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('jrnl', '0037_enjoyitem_entry'), + ] + + operations = [ + migrations.RemoveField( + model_name='enjoyitem', + name='entry', + ), + ] diff --git a/app/jrnl/migrations/0039_enjoyitem_order.py b/app/jrnl/migrations/0039_enjoyitem_order.py new file mode 100644 index 0000000..41c5324 --- /dev/null +++ b/app/jrnl/migrations/0039_enjoyitem_order.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.7 on 2019-03-15 18:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('jrnl', '0038_remove_enjoyitem_entry'), + ] + + operations = [ + migrations.AddField( + model_name='enjoyitem', + name='order', + field=models.IntegerField(default=1), + ), + ] diff --git a/app/jrnl/migrations/0040_auto_20190315_1906.py b/app/jrnl/migrations/0040_auto_20190315_1906.py new file mode 100644 index 0000000..9ce813b --- /dev/null +++ b/app/jrnl/migrations/0040_auto_20190315_1906.py @@ -0,0 +1,20 @@ +# Generated by Django 2.1.7 on 2019-03-15 19:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('jrnl', '0039_enjoyitem_order'), + ] + + operations = [ + migrations.RemoveField( + model_name='enjoyitem', + name='content_type', + ), + migrations.DeleteModel( + name='EnjoyItem', + ), + ] diff --git a/app/jrnl/migrations/0041_auto_20190315_2240.py b/app/jrnl/migrations/0041_auto_20190315_2240.py new file mode 100644 index 0000000..06b9697 --- /dev/null +++ b/app/jrnl/migrations/0041_auto_20190315_2240.py @@ -0,0 +1,28 @@ +# Generated by Django 2.1.7 on 2019-03-15 22:40 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('jrnl', '0040_auto_20190315_1906'), + ] + + operations = [ + migrations.CreateModel( + name='RelatedPost', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('slug', models.SlugField()), + ('post_model', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.ContentType')), + ], + ), + migrations.AddField( + model_name='entry', + name='related', + field=models.ManyToManyField(blank=True, to='jrnl.RelatedPost'), + ), + ] diff --git a/app/jrnl/models.py b/app/jrnl/models.py index 88fd84b..a88e79a 100644 --- a/app/jrnl/models.py +++ b/app/jrnl/models.py @@ -3,6 +3,8 @@ import os from django.dispatch import receiver from django.contrib.gis.db import models +from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey +from django.contrib.contenttypes.models import ContentType from django.urls import reverse from django.utils.functional import cached_property from django.apps import apps @@ -35,6 +37,14 @@ def image_url_replace(s): return s +class RelatedPost(models.Model): + post_model = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL) + slug = models.SlugField() + + def __str__(self): + return self.slug + + class Entry(models.Model): title = models.CharField(max_length=200) subtitle = models.CharField(max_length=200, blank=True) @@ -67,6 +77,7 @@ class Entry(models.Model): has_video = models.BooleanField(blank=True, default=False) field_notes = models.ManyToManyField(FieldNote, blank=True) books = models.ManyToManyField(Book, blank=True) + related = models.ManyToManyField(RelatedPost, blank=True) class Meta: ordering = ('-pub_date',) diff --git a/app/jrnl/views.py b/app/jrnl/views.py index 43ca2d9..7ea3e41 100644 --- a/app/jrnl/views.py +++ b/app/jrnl/views.py @@ -3,6 +3,7 @@ from django.views.generic.detail import DetailView from django.views.generic.dates import DateDetailView from django.views.generic.dates import YearArchiveView, MonthArchiveView from django.contrib.syndication.views import Feed +from django.apps import apps from django.shortcuts import get_object_or_404 from django.conf import settings from django.db.models import Q @@ -96,6 +97,11 @@ class EntryDetailView(DateDetailView): Q(location=self.location) | Q(location__in=Location.objects.filter(parent=self.location)) ).select_related().order_by('ap_id', 'ap__apclass__kind').distinct("ap") + related = [] + for obj in self.object.related.all(): + model = apps.get_model(obj.post_model.app_label, obj.post_model.model) + related.append(model.objects.get(slug=obj.slug)) + context['related'] = related return context diff --git a/app/sightings/models.py b/app/sightings/models.py index 5723776..3852b1c 100644 --- a/app/sightings/models.py +++ b/app/sightings/models.py @@ -12,7 +12,7 @@ from django.conf import settings from bs4 import BeautifulSoup from locations.models import Location -from photos.models import LuxImage +from photos.models import LuxImage, LuxImageSize from utils.next_prev import next_in_order, prev_in_order from utils.util import render_images, extract_main_image, markdown_to_html @@ -75,7 +75,7 @@ class AP(models.Model): return self.common_name def get_image_url(self): - return "%s%s" % (settings.IMAGES_URL, self.image.url.split("media")[1][8:]) + return "%s%s" % (settings.IMAGES_URL, self.image.image.url.split("media")[1][8:]) def get_absolute_url(self): return reverse("sightings:detail", kwargs={"slug": self.slug}) @@ -121,6 +121,9 @@ class AP(models.Model): main_image = extract_main_image(self.body_markdown) if main_image: self.image = main_image + s = LuxImageSize.objects.get(name="featured_jrnl") + self.image.sizes.add(s) + self.image.save() self.slug = slugify(self.common_name[:50]) super(AP, self).save(*args, **kwargs) diff --git a/design/sass/_details.scss b/design/sass/_details.scss index d5681c6..41afd04 100644 --- a/design/sass/_details.scss +++ b/design/sass/_details.scss @@ -246,6 +246,77 @@ h4.post-source { } } +.article-afterward { + @extend %clearfix; + @include constrain_narrow; + padding-bottom: 2rem; + border-bottom: 3px double #efefef; + @include breakpoint(alpha) { + .article-card-list { + display: flex; + justify-content: space-between + } + .article-card-mini { + margin-bottom: 0 + } + } + .hedtinycaps { + display: inline-block; + margin-bottom: 2.5rem; + border-bottom: 2px solid #efefef; + } +} +.article-card-list { + padding: 0 !important; + margin: 0 !important; + list-style-type: none !important; +} +.article-card-mini, .detail .article-card-mini { + margin-left: 0; + margin-right: 0; + margin-bottom: 2rem; + max-width: 100%; + a { text-decoration: none;} + .post-title { + @include fontsize(24); + text-align: center; + line-height: 1; + margin: 0; + } + .post-subtitle { + @include fontsize(18); + text-align: center; + font-family: $fancy_serif; + font-style: italic; + font-weight: normal; + margin: .25rem auto 0; + } + .post-summary, .post-date{ + text-align: center; + display: inline-block; + line-height: 0.6 !important; + color: #b6b6b6; + } + @include breakpoint(omega) { + max-width: 200px; + margin-bottom: 0; + } + @include breakpoint(beta) { + max-width: 235px; + } +} +.post-mini-image { + max-height: 220px; + overflow: hidden; + @include breakpoint(beta) { + margin-bottom: 1rem; + } + img { + margin-top: -20%; + } +} + + .entry-footer { @extend %clearfix; @include constrain_narrow; diff --git a/design/sass/_footer.scss b/design/sass/_footer.scss index ed1635c..08c9942 100644 --- a/design/sass/_footer.scss +++ b/design/sass/_footer.scss @@ -9,7 +9,9 @@ footer { margin-bottom: 1.2em; } } - ul { + .footer-nav { + list-style-type: none !important; + margin-left: 0 !important; border-top: 1px $brown dotted; border-bottom: 1px $brown dotted; padding: .5rem 0; @@ -73,3 +75,9 @@ footer { text-decoration: none; width: 70px; } +#license { + @include fancy_sans; + @include fontsize(12); + text-transform: none; + letter-spacing: normal; +} diff --git a/design/sass/_mixins.scss b/design/sass/_mixins.scss index dd6f257..8c936eb 100644 --- a/design/sass/_mixins.scss +++ b/design/sass/_mixins.scss @@ -14,7 +14,7 @@ $secondary-link-color: #838383; $archive_p_line_height: 1.6; //$light; -$narrow-beta-width: 640px; +$narrow-beta-width: 720px; $narrow-max-width: 750px; $max_width: 1440px; diff --git a/design/sass/_typography.scss b/design/sass/_typography.scss new file mode 100644 index 0000000..b4e3793 --- /dev/null +++ b/design/sass/_typography.scss @@ -0,0 +1,10 @@ +.hedtinycaps { + @include fontsize(16); + @include fancy_sans; + text-transform: uppercase; + letter-spacing: 1px; +} +.article-afterward > .hedtinycaps, p > .hedtinycaps { + text-align: left; +} + diff --git a/design/sass/screenv9.scss b/design/sass/screenv9.scss index d594e28..312018c 100644 --- a/design/sass/screenv9.scss +++ b/design/sass/screenv9.scss @@ -4,7 +4,6 @@ @import "_global.scss"; @import "_pagination.scss"; @import "_header.scss"; -@import "_footer.scss"; @import "_archives.scss"; @import "_details.scss"; @import "_images.scss"; @@ -16,3 +15,5 @@ @import "_photos.scss"; @import "_notes.scss"; @import "_forms.scss"; +@import "_typography.scss"; +@import "_footer.scss"; diff --git a/design/templates/archives/homepage-light.html b/design/templates/archives/homepage-light.html index 1964795..1021885 100644 --- a/design/templates/archives/homepage-light.html +++ b/design/templates/archives/homepage-light.html @@ -2,7 +2,7 @@ {% load typogrify_tags %} {% block sitename %} - Luxagraf + Luxagraf: thoughts on ecology, culture, travel, photography, walking and other ephemera {%endblock%} {%block extrahead%} diff --git a/design/templates/base.html b/design/templates/base.html index 495a496..bf78846 100644 --- a/design/templates/base.html +++ b/design/templates/base.html @@ -14,7 +14,7 @@ title="Luxagraf RSS feed" href="https://luxagraf.net/rss/"> {%block stylesheet%}{%endblock%} @@ -44,7 +44,7 @@ {% block primary %}{% endblock %} {% block extrabody %}{% endblock %}