summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/jrnl/admin.py17
-rw-r--r--app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py5
-rw-r--r--app/jrnl/migrations/0036_enjoyitem.py23
-rw-r--r--app/jrnl/migrations/0037_enjoyitem_entry.py20
-rw-r--r--app/jrnl/migrations/0038_remove_enjoyitem_entry.py17
-rw-r--r--app/jrnl/migrations/0039_enjoyitem_order.py18
-rw-r--r--app/jrnl/migrations/0040_auto_20190315_1906.py20
-rw-r--r--app/jrnl/migrations/0041_auto_20190315_2240.py28
-rw-r--r--app/jrnl/models.py11
-rw-r--r--app/jrnl/views.py6
-rw-r--r--app/sightings/models.py7
-rw-r--r--design/sass/_details.scss71
-rw-r--r--design/sass/_footer.scss10
-rw-r--r--design/sass/_mixins.scss2
-rw-r--r--design/sass/_typography.scss10
-rw-r--r--design/sass/screenv9.scss3
-rw-r--r--design/templates/archives/homepage-light.html2
-rw-r--r--design/templates/base.html4
-rw-r--r--design/templates/jrnl/entry_detail.html26
-rw-r--r--design/templates/lib/img_archive.html2
20 files changed, 291 insertions, 11 deletions
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
@@ -70,6 +70,11 @@ class Migration(migrations.Migration):
),
migrations.AddField(
model_name='entry',
+ name='field_notes',
+ field=models.ManyToManyField(blank=True, to='fieldnotes.FieldNote'),
+ ),
+ migrations.AddField(
+ model_name='entry',
name='books',
field=models.ManyToManyField(blank=True, to='books.Book'),
),
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 %}
<head itemscope itemtype="http://schema.org/WebSite">
- <title itemprop='name'>Luxagraf</title>
+ <title itemprop='name'>Luxagraf: thoughts on ecology, culture, travel, photography, walking and other ephemera</title>
<link rel="canonical" href="https://luxagraf.net/" itemprop="url">{%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%}<link rel="stylesheet"
- href="/media/screenv9.css"
+ href="/media/screenv9.css?{% now "u" %}"
media="screen">{%endblock%}
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="manifest" href="/manifest.webmanifest" />
@@ -44,7 +44,7 @@
{% block primary %}{% endblock %}
{% block extrabody %}{% endblock %}
<footer class="bl">
- <ul>
+ <ul class="footer-nav">
<li><a href="/blogroll" title="Sites that inspire us">Blogroll</a></li>
<li><a href="/contact/" title="contact luxagraf">Contact</a></li>
<li>Follow Along:
diff --git a/design/templates/jrnl/entry_detail.html b/design/templates/jrnl/entry_detail.html
index 7d7e2a3..c19add1 100644
--- a/design/templates/jrnl/entry_detail.html
+++ b/design/templates/jrnl/entry_detail.html
@@ -121,6 +121,32 @@ class="detail {%if t == 1 or t == 3 or t == 5 %}double{%else%}single{%endif%}{%i
</ul>
</nav>{%endwith%}{%endwith%}
</div>
+ <div class="article-afterward related">
+ <h6 class="hedtinycaps">You might also enjoy</h6>
+ <ul class="article-card-list">{% for object in related %}
+ <li class="article-card-mini"><a href="{{object.get_absolute_url}}" title="{{object.title}}">
+ <div class="post-image post-mini-image">
+ {% if object.featured_image %}
+ {% include "lib/img_archive.html" with image=object.featured_image nolightbox=True %}
+ {% elif object.image %}
+ {% include "lib/img_archive.html" with image=object.image nolightbox=True %}
+ {% else %}
+ <img src="{{object.get_image_url}}" alt="{{ object.title }}" class="u-photo post-image" itemprop="image" />{%endif%}
+ </div>
+ <h4 class="p-name entry-title post-title" itemprop="headline">{% if object.title %}{{object.title|safe|smartypants|widont}}{% else %}{{object.common_name}}{%endif%}</h4>
+ {% if object.subtitle%}<h5 class="post-subtitle">{{object.subtitle|safe|smartypants}}</h5>{%endif%}
+ <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p>
+ <p class="post-summary">
+ <span class="p-location h-adr adr post-location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place">
+ {% if object.location.country_name == "United States" %}{{object.location.state_name}}{%else%}{{object.location.country_name}}{%endif%}
+ </span>
+ &ndash;
+ <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}"><span>{{object.pub_date|date:" Y"}}</span></time>
+ </p>
+ </a>
+ </li>
+ {% endfor %}</ul>
+ </div>
{% comment %} <div class="mailing-list--wrapper">
<h5>If you enjoyed this, you should join the mailing&nbsp;list&hellip;</h5>
diff --git a/design/templates/lib/img_archive.html b/design/templates/lib/img_archive.html
index c256ebe..a512930 100644
--- a/design/templates/lib/img_archive.html
+++ b/design/templates/lib/img_archive.html
@@ -2,4 +2,4 @@
srcset="{{image.get_featured_jrnl}} 520w, {{image.get_picwide_sm}} 720w"
src="{{image.get_featured_jrnl}}"
alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}"
- data-jslghtbx="{{image.get_image_by_size}}" data-jslghtbx-group="group" {% if caption%}data-jslghtbx-caption="{{image.caption}}"{%endif%}>
+ {% if not nolightbox %}data-jslghtbx="{{image.get_image_by_size}}" data-jslghtbx-group="group" {% if caption%}data-jslghtbx-caption="{{image.caption}}"{%endif%}{%endif%}>