summaryrefslogtreecommitdiff
path: root/app/pages
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2021-08-14 09:39:08 -0400
committerluxagraf <sng@luxagraf.net>2021-08-14 09:39:08 -0400
commit9327e01c60b114286f5a142552aae60843029a48 (patch)
tree7f353f4299d50013c3b90f7b749fc6ab211b32d4 /app/pages
parent0feb366b10cf422f12d18fa753e5d876120f4195 (diff)
initial commit
Diffstat (limited to 'app/pages')
-rw-r--r--app/pages/__init__.py0
-rw-r--r--app/pages/admin.py55
-rw-r--r--app/pages/build.py25
-rw-r--r--app/pages/migrations/0001_initial.py49
-rw-r--r--app/pages/migrations/__init__.py0
-rw-r--r--app/pages/models.py61
-rw-r--r--app/pages/static.py123
-rw-r--r--app/pages/templates/pages/discursive/homepage.html20
-rw-r--r--app/pages/templates/pages/discursive/page_detail.html30
-rw-r--r--app/pages/templates/pages/discursive/page_detail.txt7
-rw-r--r--app/pages/templates/pages/luxagraf/homepage.html98
-rw-r--r--app/pages/templates/pages/luxagraf/page_detail.html37
-rw-r--r--app/pages/templates/pages/luxagraf/page_detail.txt8
-rw-r--r--app/pages/urls.py13
-rw-r--r--app/pages/views.py40
15 files changed, 566 insertions, 0 deletions
diff --git a/app/pages/__init__.py b/app/pages/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/pages/__init__.py
diff --git a/app/pages/admin.py b/app/pages/admin.py
new file mode 100644
index 0000000..3c7d900
--- /dev/null
+++ b/app/pages/admin.py
@@ -0,0 +1,55 @@
+from django.contrib import admin
+from utils.widgets import LGEntryForm
+
+from django import forms
+from django.forms import Textarea
+from django.db import models
+
+from pages.models import Page, HomePage
+
+
+class PageEntryForm(forms.ModelForm):
+ class Meta:
+ model = Page
+ fields = '__all__'
+ widgets = {
+ 'body_markdown': forms.Textarea(attrs={'rows': 50, 'cols': 100}),
+ }
+
+
+@admin.register(Page)
+class PageAdmin(admin.ModelAdmin):
+ form = LGEntryForm
+ list_display = ('title', 'site', 'slug', 'path', 'app', 'build')
+ search_fields = ['title', 'body_markdown']
+ prepopulated_fields = {"slug": ('title',)}
+ fieldsets = (
+ ('Page', {
+ 'fields': ('title', 'sub_title', 'body_markdown', ('build', 'enable_comments'), ('site','slug', 'path', 'app'), 'featured_image', 'pub_date'),
+ 'classes': ('show', 'extrapretty', 'wide')
+ }),
+ ('Metadata', {
+ 'classes': ('collapse closed',),
+ 'fields': ('meta_description',),
+ })
+ )
+
+ class Media:
+ js = ('image-loader.js', 'product-loader.js', 'next-prev-links.js')
+ css = {
+ "all": ("my_styles.css",)
+ }
+
+
+
+
+@admin.register(HomePage)
+class HomePageAdmin(admin.ModelAdmin):
+ form = LGEntryForm
+ filter_horizontal = ('popular',)
+
+ class Media:
+ js = ('image-loader.js', 'next-prev-links.js')
+ css = {
+ "all": ("my_styles.css",)
+ }
diff --git a/app/pages/build.py b/app/pages/build.py
new file mode 100644
index 0000000..9545ce3
--- /dev/null
+++ b/app/pages/build.py
@@ -0,0 +1,25 @@
+from django.template.loader import render_to_string
+from django.template import Context
+from django.urls import reverse
+from django.conf import settings
+
+from builder.base import BuildNew
+
+
+class BuildPages(BuildNew):
+
+ def build(self):
+ self.build_detail_view()
+
+ def get_model_queryset(self):
+ return self.model.objects.filter(build=True,site=self.site)
+
+
+class BuildHome(BuildNew):
+
+ def get_model_queryset(self):
+ return self.model.objects.get(pk=1)
+
+ def build(self):
+ response = self.client.get('/')
+ self.write_file('/', response.content)
diff --git a/app/pages/migrations/0001_initial.py b/app/pages/migrations/0001_initial.py
new file mode 100644
index 0000000..61213e1
--- /dev/null
+++ b/app/pages/migrations/0001_initial.py
@@ -0,0 +1,49 @@
+# Generated by Django 3.1.3 on 2020-11-30 22:44
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('sites', '0002_alter_domain_unique'),
+ ('media', '__first__'),
+ ('posts', '__first__'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Page',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=200)),
+ ('sub_title', models.CharField(blank=True, max_length=300)),
+ ('slug', models.SlugField()),
+ ('body_html', models.TextField(blank=True)),
+ ('body_markdown', models.TextField()),
+ ('meta_description', models.CharField(blank=True, max_length=256)),
+ ('path', models.CharField(blank=True, max_length=200)),
+ ('app', models.CharField(blank=True, max_length=50)),
+ ('build', models.BooleanField(default=True)),
+ ('enable_comments', models.BooleanField(default=False)),
+ ('pub_date', models.DateTimeField(blank=True, null=True, verbose_name='Date published')),
+ ('featured_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='media.luximage')),
+ ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='HomePage',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('image_offset_vertical', models.CharField(help_text='add negative top margin to shift image (include css unit)', max_length=20)),
+ ('tag_line', models.CharField(blank=True, max_length=200, null=True)),
+ ('template_name', models.CharField(blank=True, help_text='full path', max_length=200, null=True)),
+ ('featured', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='banner', to='posts.post')),
+ ('featured_image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='media.luximage')),
+ ('popular', models.ManyToManyField(related_name='popular', to='posts.Post')),
+ ],
+ ),
+ ]
diff --git a/app/pages/migrations/__init__.py b/app/pages/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/pages/migrations/__init__.py
diff --git a/app/pages/models.py b/app/pages/models.py
new file mode 100644
index 0000000..7cf90ba
--- /dev/null
+++ b/app/pages/models.py
@@ -0,0 +1,61 @@
+import re
+from django.db import models
+from django.contrib.sitemaps import Sitemap
+from django.contrib.sites.models import Site
+
+from media.models import LuxImage
+from posts.models import Post
+from utils.util import markdown_to_html, render_images
+
+
+class Page(models.Model):
+ title = models.CharField(max_length=200)
+ sub_title = models.CharField(max_length=300, blank=True)
+ slug = models.SlugField()
+ body_html = models.TextField(blank=True)
+ body_markdown = models.TextField()
+ meta_description = models.CharField(max_length=256, blank=True)
+ path = models.CharField(max_length=200, blank=True)
+ app = models.CharField(max_length=50, blank=True)
+ build = models.BooleanField(default=True)
+ enable_comments = models.BooleanField(default=False)
+ site = models.ForeignKey(Site, on_delete=models.CASCADE)
+ featured_image = models.ForeignKey(LuxImage, on_delete=models.CASCADE, null=True, blank=True)
+ pub_date = models.DateTimeField('Date published', null=True, blank=True)
+
+ def __str__(self):
+ return self.title
+
+ def get_absolute_url(self):
+ if self.path:
+ return "/%s/%s" % (self.path, self.slug)
+ else:
+ return "/%s" % (self.slug)
+
+ def save(self):
+ # run markdown
+ md = render_images(self.body_markdown)
+ self.body_html = markdown_to_html(md)
+ super(Page, self).save()
+
+
+class HomePage(models.Model):
+ """
+ simple model to control the featured article on the homepage
+ also allows me to fudge the "popular" section to be what I want
+ """
+ image_offset_vertical = models.CharField(max_length=20, help_text="add negative top margin to shift image (include css unit)")
+ featured_image = models.ForeignKey(LuxImage, on_delete=models.CASCADE)
+ tag_line = models.CharField(max_length=200, null=True, blank=True)
+ featured = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="banner")
+ popular = models.ManyToManyField(Post, related_name="popular")
+ template_name = models.CharField(max_length=200, help_text="full path", null=True, blank=True)
+
+
+class PageSitemap(Sitemap):
+ changefreq = "never"
+ priority = 1.0
+ protocol = "https"
+
+ def items(self):
+ return Page.objects.filter(build=True)
diff --git a/app/pages/static.py b/app/pages/static.py
new file mode 100644
index 0000000..3ef1a71
--- /dev/null
+++ b/app/pages/static.py
@@ -0,0 +1,123 @@
+from django.db import models
+from django.contrib.sitemaps import Sitemap
+import markdown
+
+
+import os
+import yaml
+from django.conf import settings
+from django.template.loader import render_to_string
+from django.template import Context
+from mdx_attr_list.mdx_attr_list import AttrListExtension
+
+
+def markdown_processor(txt):
+ md = markdown.Markdown(
+ extensions=[AttrListExtension(),'footnotes',],
+ output_format='html5',
+ safe_mode=False
+ )
+ return md.convert(txt)
+'''
+class Page(models.Model):
+ title = models.CharField(max_length=200)
+ slug = models.SlugField()
+ body_html = models.TextField(blank=True)
+ body_markdown = models.TextField()
+ meta_description = models.CharField(max_length=256, null=True, blank=True)
+
+ def __unicode__(self):
+ return self.title
+
+ def get_absolute_url(self):
+ return "/%s/" % (self.slug)
+
+ def save(self):
+ #run markdown
+ self.body_html = markdown_processor(self.body_markdown)
+ super(Page, self).save()
+'''
+
+class PageSitemap(Sitemap):
+ changefreq = "never"
+ priority = 1.0
+ protocol = "https"
+
+ def items(self):
+ p = PageGenerator(settings.PROJ_ROOT + '_pages')
+ return p.objects(include_in_sitemap=True)
+ #return Page.objects.all()
+
+
+class PageGenerator(object):
+
+ def __init__(self, path, *args, **kwargs):
+ self._objects = []
+ for (dirpath, dirnames, filenames) in os.walk(path):
+ self.dirpath = dirpath
+ self.file_list = filter(lambda item: not (item.startswith('.') or item.endswith('~') or item.endswith('.md')), filenames)
+ self.get_files()
+
+ def get_files(self):
+ for f in self.file_list:
+ p = Page(self.dirpath + '/' + f)
+ self._objects.append(p)
+
+ def objects(self, *args, **kwargs):
+ filtered_list = []
+ if kwargs:
+ for item in self._objects:
+ found = False
+ for k, v in kwargs.items():
+ if getattr(item, k) == v and not found:
+ found = True
+ filtered_list.append(item)
+ elif getattr(item, k) != v and found:
+ filtered_list.remove(item)
+ return filtered_list
+ return self._objects
+
+ def write_files(self):
+ for obj in self.objects():
+ c = Context({'object': obj, 'SITE_URL': settings.SITE_URL})
+ t = render_to_string(["details/%s.html" % obj.template], c)
+ s = render_to_string('details/page.txt', c)
+ _FileWriter('', t, ext="html", filename=obj.slug)
+ _FileWriter('', s, ext="txt", filename=obj.slug)
+
+
+class _FileWriter(object):
+ """
+ Given a path and text object; write the page to disc
+ """
+ def __init__(self, path, text_object, ext='html', filename='index'):
+ self.path = '%s%s' % (settings.FLATFILES_ROOT, path)
+ if not os.path.isdir(self.path):
+ os.makedirs(self.path)
+ fpath = '%s%s.%s' % (self.path, filename, ext)
+ self.write(fpath, text_object)
+
+ def write(self, fpath, text_object):
+ file = open(fpath, 'wb')
+ file.write(text_object.encode('utf-8'))
+ file.close()
+
+
+class _FileLoader(object):
+
+ def __init__(self, filename, *args, **kwargs):
+ self.filename = filename
+ metadata = self.read()
+ for k, v in metadata.items():
+ setattr(self, k, v)
+ if self.body_markdown:
+ self.body_html = markdown_processor(self.body_markdown)
+
+ def read(self):
+ with open(self.filename, "r", encoding="utf-8") as f:
+ contents = f.read()
+ metayaml, self.body_markdown = contents.split('\n---')
+ return yaml.load(metayaml)
+
+class Page(_FileLoader):
+ pass
diff --git a/app/pages/templates/pages/discursive/homepage.html b/app/pages/templates/pages/discursive/homepage.html
new file mode 100644
index 0000000..68490ba
--- /dev/null
+++ b/app/pages/templates/pages/discursive/homepage.html
@@ -0,0 +1,20 @@
+{% extends 'discursive_base.html' %}
+{% load typogrify_tags %}
+{% load comments %}
+{% block pagetitle %}Learn Discursive Meditation{% endblock %}
+{% block metadescription %}{{object.meta_description}}{% endblock %}
+{%block bodyclass%}detail{%endblock%}
+{%block bodyid%}{%endblock%}
+{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %}
+{% block content %}<main>
+ <article>
+ <header class="post-header">
+ <h1 class="post-title">{{object.title}}</h1>
+ {%if object.sub_title %}<h2 class="post-subtitle">{{object.sub_title}}</h2>{%endif%}
+ </header>
+ <div class="post-article">
+ {{object.body_html|safe|smartypants|widont}}
+ </div>
+ </article>
+ </main>
+{% endblock %}
diff --git a/app/pages/templates/pages/discursive/page_detail.html b/app/pages/templates/pages/discursive/page_detail.html
new file mode 100644
index 0000000..8941cd2
--- /dev/null
+++ b/app/pages/templates/pages/discursive/page_detail.html
@@ -0,0 +1,30 @@
+{% extends 'discursive_base.html' %}
+{% load typogrify_tags %}
+{% load comments %}
+{% block pagetitle %}{{object.title}}{% endblock %}
+{% block metadescription %}{{object.meta_description}}{% endblock %}
+{%block htmlclass%}class="detail"{%endblock%}
+{%block bodyid%}{{object.title|slugify}}{%endblock%}
+{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %}
+{% block content %}<main>
+ <article>
+ <header class="post-header">
+ <h1 class="post-title">{{object.title}}</h1>
+ {%if object.sub_title %}<h2 class="post-subtitle">{{object.sub_title}}</h2>{%endif%}
+ </header>
+ <div class="post-article">
+ {{object.body_html|safe|smartypants|widont}}
+ </div>
+ </article>
+ {% if object.enable_comments %}
+{% get_comment_count for object as comment_count %}
+{%if comment_count > 0 %}
+<p class="comments--header">{{comment_count}} Comment{{ comment_count|pluralize }}</p>
+{% render_comment_list for object %}
+{%endif%}
+<div class="comment--form--wrapper {%if comment_count > 0%}comment-form-border{%endif%}">
+{% render_comment_form for object %}
+</div>
+{%endif%}
+ </main>
+{% endblock %}
diff --git a/app/pages/templates/pages/discursive/page_detail.txt b/app/pages/templates/pages/discursive/page_detail.txt
new file mode 100644
index 0000000..bbeb715
--- /dev/null
+++ b/app/pages/templates/pages/discursive/page_detail.txt
@@ -0,0 +1,7 @@
+{{object.title|safe}}
+{% for letter in object.title %}={%endfor%}
+
+ <https://{{object.site.domain}}{{object.get_absolute_url}}>
+ {{object.pub_date|date:"l, d F Y"}}
+
+{{object.body_markdown|safe}}
diff --git a/app/pages/templates/pages/luxagraf/homepage.html b/app/pages/templates/pages/luxagraf/homepage.html
new file mode 100644
index 0000000..c8075ea
--- /dev/null
+++ b/app/pages/templates/pages/luxagraf/homepage.html
@@ -0,0 +1,98 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% block sitename %}
+<head itemscope itemtype="http://schema.org/WebSite">
+ <title itemprop='name'>Luxagraf: thoughts on ecology, culture, travel, photography, walking and other ephemera</title>
+ <link rel="canonical" href="https://luxagraf.net/">{%endblock%}
+
+ {%block extrahead%}
+<style>
+@media screen and (min-width: 1440px) {
+ .banner .post-image img {
+ margin-top: {{object.image_offset_vertical}};
+ }
+}
+</style>
+{%endblock%}
+{%block bodyid%}id="home" class="archive"{%endblock%}
+
+{% block primary %}<div class="banner">{% with object=homepage.featured %}
+ <article class="h-entry hentry" itemscope itemType="http://schema.org/Article">
+ <figure class="post-image">
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">{%with image=homepage.featured_image%}
+ <img class="u-photo" itemprop="image" sizes="(max-width: 960px) 100vw"
+ srcset="{{image.get_srcset}}"
+ src="{{image.get_src}}"
+ alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}">
+ </a>{%endwith%}
+ <figcaption>
+ <div class="hero-text-wrapper">
+ <h1 class="p-name entry-title post-title" itemprop="headline">{%if object.template_name == 1 or object.template_name == 3 %}{{object.title|smartypants|safe}}{%else%}{{object.title|smartypants|safe}}{%endif%}</h1>
+ <h2 class="post-subtitle">{% if object.subtitle %}{{object.subtitle|smartypants|safe}}{%else%}{{homepage.tag_line|safe|smartypants}}{%endif%}</h2>
+ <aside class="p-location h-adr adr post-location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place">
+ <div class="h-adr" itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">{% if object.location.country_name == "United States" %}<span class="p-locality locality" itemprop="addressLocality">{{object.location.name|smartypants|safe}}</span>, <a class="p-region region" href="/jrnl/united-states/" title="travel writing from the United States">{{object.location.state_name|safe}}</a>, <span class="p-country-name" itemprop="addressCountry">U.S.</span>{%else%}<span class="p-region" itemprop="addressRegion">{{object.location.name|smartypants|safe}}</span>, <a class="p-country-name country-name" href="/jrnl/{{object.location.country_slug}}/" title="travel writing from {{object.location.country_name}}"><span itemprop="addressCountry">{{object.location.country_name|safe}}</span></a>{%endif%}</div>
+ </aside>
+ <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time>
+ <span class="hide" itemprop="author" itemscope itemtype="http://schema.org/Person">by <a class="p-author h-card" href="/about"><span itemprop="name">Scott Gilbertson</span></a></span>
+ <a href="{{object.get_absolute_url}}" class="u-url btn" title="{%if object.title_keywords%}{{object.title_keywords}}{%else%}{{object.title}}{%endif%}">Read</a>
+ </div>
+ </figcaption>
+ </figure>
+ </article>{% endwith %}
+ </div>
+ <section class="bio-short">
+ <h2 class="homepage-section-header">About Luxagraf</h2>
+ <img src="/media/img/usa-resize.svg" alt="map of travels" class="homepage-map-img" />
+ <p>We’re a family of five living full time in a vintage 1969 Dodge Travco motorhome. We’ve been at it for three years now. People always ask: <a href="https://luxagraf.net/1969-dodge-travco-motorhome">What's it like for five people to live in a 26ft RV</a>? <a href="https://luxagraf.net/essay/why-a-vintage-rv">Why do we live this way</a>?</p>
+ <p>The short answer is simple: because we like it and we can. If you want more than a soundbite, <a href="/jrnl/">read through the journal</a>. If you like it, sign up for the newsletter, <a href="/newsletter/friends/"><em>Friends of a Long Year</em></a>. I'd also <a href="/feed.xml">subscribe to the RSS feed</a>, but that's just <a href="/about">me</a>. <!-- If you’re interested there’s a guide section with some <a href="/guides/">advice, tips and tricks for those who’d aspire to live full time in a van or RV</a> --></p>
+ </section>
+ <section class="recent-popular">
+ <div class="recent">
+ <h2 class="homepage-section-header">Recent</h2>
+ <div class="archive-grid">{% for object in object_list %}
+ <article class="h-entry hentry archive-card {% cycle 'odd' 'even' %} {% cycle 'first' 'second' 'third' %}" itemscope itemType="http://schema.org/Article">
+ <div class="post-image">
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">{% if object.featured_image %}
+ {% include "lib/img_archive.html" with image=object.featured_image %}
+ {%else%}
+ <img src="{{object.get_image_url}}" alt="{{ object.title }}" class="u-photo post-image" itemprop="image" />{%endif%}</a>
+ </div>
+ <h3 class="p-name entry-title post-title" itemprop="headline"><a href="{{object.get_absolute_url}}" class="u-url" title="{%if object.title_keywords%}{{object.title_keywords}}{%else%}{{object.title}}{%endif%}">{{object.title|safe|smartypants|widont}}</a></h3>
+ <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>
+ <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time>
+ <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" %}<span class="p-locality locality">{{object.location.name|smartypants|safe}}</span>, <a class="p-region region" href="/jrnl/united-states/" title="travel writing from the United States">{{object.location.state_name}}</a>, <span class="p-country-name">U.S.</span>{%else%}<span class="p-region">{{object.location.name|smartypants|safe}}</span>, <a class="p-country-name country-name" href="/jrnl/{{object.location.country_slug}}/" title="travel writing from {{object.location.country_name}}">{{object.location.country_name}}</a>{%endif%}
+ </span>
+ </p>
+ </article> {% endfor %}
+ </div>
+ </div>
+ <div class="popular">
+ <h2 class="homepage-section-header">Popular</h2>
+ <div class="archive-grid">{% for object in homepage.popular.all %}
+ <article class="h-entry hentry archive-card {% cycle 'odd' 'even' %} {% cycle 'first' 'second' 'third' %}" itemscope itemType="http://schema.org/Article">
+ <div class="post-image">
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">{% if object.featured_image %}
+ {% include "lib/img_archive.html" with image=object.featured_image %}
+ {%else%}
+ <img src="{{object.get_image_url}}" alt="{{ object.title }}" class="u-photo post-image" itemprop="image" />{%endif%}</a>
+ </div>
+ <h3 class="p-name entry-title post-title" itemprop="headline"><a href="{{object.get_absolute_url}}" class="u-url" title="{%if object.title_keywords%}{{object.title_keywords}}{%else%}{{object.title}}{%endif%}">{{object.title|safe|smartypants|widont}}</a></h3>
+ <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>
+ <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time>
+ <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" %}<span class="p-locality locality">{{object.location.name|smartypants|safe}}</span>, <a class="p-region region" href="/jrnl/united-states/" title="travel writing from the United States">{{object.location.state_name}}</a>, <span class="p-country-name">U.S.</span>{%else%}<span class="p-region">{{object.location.name|smartypants|safe}}</span>, <a class="p-country-name country-name" href="/jrnl/{{object.location.country.slug}}/" title="travel writing from {{object.location.country_name}}">{{object.location.country_name}}</a>{%endif%}
+ </span>
+ </p>
+ </article> {% endfor %}
+ </div>
+ </div>
+ </section>
+ <section>
+ <h5 class="homepage-next"><a href="/jrnl/">Browse the Archives</a></h5>
+ </section>
+{% endblock %}
+
+{% block js %}{% comment %} <script async src="/media/js/hyphenate.min.js" type="text/javascript"></script>{% endcomment%}{% endblock%}
diff --git a/app/pages/templates/pages/luxagraf/page_detail.html b/app/pages/templates/pages/luxagraf/page_detail.html
new file mode 100644
index 0000000..4644386
--- /dev/null
+++ b/app/pages/templates/pages/luxagraf/page_detail.html
@@ -0,0 +1,37 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% load comments %}
+{% block pagetitle %}Luxagraf | {{object.title}}{% endblock %}
+{% block metadescription %}{{object.meta_description}}{% endblock %}
+{%block htmlclass%}class="detail"{%endblock%}
+{%block bodyid%}id="{{object.title|slugify}}"{%endblock%}
+{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %}
+{% block primary %}<main>
+ <article>
+ <header class="post-header">
+ <h1 class="post-title">{{object.title}}</h1>
+ {%if object.sub_title %}<h2 class="post-subtitle">{{object.sub_title}}</h2>{%endif%}
+ </header>
+ <div class="post-article">
+ {{object.body_html|safe|smartypants|widont}}
+ </div>
+ </article>
+ {% if object.enable_comments %}
+{% get_comment_count for object as comment_count %}
+{%if comment_count > 0 %}
+<p class="comments--header">{{comment_count}} Comment{{ comment_count|pluralize }}</p>
+{% render_comment_list for object %}
+{%endif%}
+<div class="comment--form--wrapper {%if comment_count > 0%}comment-form-border{%endif%}">
+{% render_comment_form for object %}
+</div>
+{%endif%}
+ </main>
+{% endblock %}
+{% block js %}
+<script src="/media/js/lightbox.js" type="text/javascript"></script>
+<script>var opts={captions:true,onload:function(){var im=document.getElementById("jslghtbx-contentwrapper");var link=im.appendChild(document.createElement('a'))
+link.href=im.firstChild.src;link.innerHTML="open ";link.target="_blank";link.setAttribute('class','p-link');im.appendChild(link);}};var lightbox=new Lightbox();lightbox.load(opts);</script>
+{% endblock %}
+
+
diff --git a/app/pages/templates/pages/luxagraf/page_detail.txt b/app/pages/templates/pages/luxagraf/page_detail.txt
new file mode 100644
index 0000000..547ce79
--- /dev/null
+++ b/app/pages/templates/pages/luxagraf/page_detail.txt
@@ -0,0 +1,8 @@
+{{object.title|safe}}
+{% for letter in object.title %}={%endfor%}
+
+ by Scott Gilbertson
+ <{{SITE_URL}}{{object.get_absolute_url}}>
+ {{object.pub_date|date:"l, d F Y"}}
+
+{{object.body_markdown|safe}}
diff --git a/app/pages/urls.py b/app/pages/urls.py
new file mode 100644
index 0000000..c40eee0
--- /dev/null
+++ b/app/pages/urls.py
@@ -0,0 +1,13 @@
+from django.urls import path, re_path
+
+from . import views
+
+app_name = "pages"
+
+urlpatterns = [
+ path(
+ r'',
+ views.PageDetailView.as_view(),
+ name="detail"
+ ),
+]
diff --git a/app/pages/views.py b/app/pages/views.py
new file mode 100644
index 0000000..cb91f9b
--- /dev/null
+++ b/app/pages/views.py
@@ -0,0 +1,40 @@
+from utils.views import LuxDetailView
+from django.views.generic import DetailView
+
+from posts.models import Post, PostType
+from .models import Page, HomePage
+
+
+class PageDetailView(LuxDetailView):
+ model = Page
+
+ def get_template_names(self):
+ obj = self.get_object()
+ return ["pages/%s/%s.html" % (obj.site.name, obj.slug), 'pages/%s/page_detail.html'% obj.site.name]
+
+
+class PageDetailTXTView(LuxDetailView):
+ model = Page
+ slug_field = "slug"
+
+ def get_template_names(self):
+ obj = self.get_object()
+ return 'pages/%s/page_detail.txt'% obj.site.name
+
+
+class HomePageList(DetailView):
+ """
+ Return a main entry and list of Entries in reverse chronological order
+ """
+ model = HomePage
+
+ def get_template_names(self):
+ return ["pages/%s.html" % self.template_name, 'pages/luxagraf/homepage.html']
+
+ def get_context_data(self, **kwargs):
+ # Call the base implementation first to get a context
+ context = super(HomePageList, self).get_context_data(**kwargs)
+ context['object_list'] = Post.objects.filter(post_type=PostType.JRNL).filter(status__exact=1).order_by('-pub_date').exclude().select_related('location').select_related('featured_image')[1:9]
+ return context
+
+