Add a "list all reviews" page
authorAlex Chan <alex@alexwlchan.net>
Sun, 2 Feb 2020 17:08:25 +0000 (17:08 +0000)
committerAlex Chan <alex@alexwlchan.net>
Sun, 2 Feb 2020 17:08:25 +0000 (17:08 +0000)
scripts/render_html.py
src/static/style.css
templates/_book_cover.html [new file with mode: 0644]
templates/list_reviews.html [new file with mode: 0644]
templates/review.html
templates/reviews.html [deleted file]

index 051befc..e0edc1e 100755 (executable)
@@ -1,7 +1,9 @@
 #!/usr/bin/env python
 
+import datetime
 import os
 import pathlib
+import re
 import subprocess
 import sys
 
@@ -39,6 +41,9 @@ class ReviewEntry:
     book = attr.ib()
     review = attr.ib()
 
+    def out_path(self):
+        return self.path.relative_to("src").with_suffix("")
+
 
 def get_review_entry_from_path(path):
     post = frontmatter.load(path)
@@ -68,10 +73,41 @@ def render_markdown(text):
     return markdown.markdown(text)
 
 
+def render_date(date_value):
+    if isinstance(date_value, datetime.date):
+        return date_value.strftime("%d %B %Y")
+
+    date_match = re.match(
+        r"^(?P<year>\d{4})-(?P<month>\d{2})(?:-(?P<day>\d{2}))?$", date_value
+    )
+    assert date_match is not None, date_value
+
+    date_obj = datetime.datetime(
+        year=int(date_match.group("year")),
+        month=int(date_match.group("month")),
+        day=int(date_match.group("day") or "1")
+    )
+
+    if date_match.group("day"):
+        return date_obj.strftime("%d %B %Y")
+    else:
+        return date_obj.strftime("%B %Y")
+
+
+def render_individual_review(env, *, review_entry):
+    template = env.get_template("review.html")
+    html = template.render(review_entry=review_entry)
+
+    out_name = review_entry.out_path() / "index.html"
+    out_path = pathlib.Path("_html") / out_name
+    out_path.parent.mkdir(exist_ok=True, parents=True)
+    out_path.write_text(html)
+
+
 if __name__ == "__main__":
     all_reviews = list(get_reviews())
     all_reviews = sorted(
-        all_reviews, key=lambda rev: rev.review.date_read, reverse=True
+        all_reviews, key=lambda rev: str(rev.review.date_read), reverse=True
     )
 
     env = Environment(
@@ -80,15 +116,16 @@ if __name__ == "__main__":
     )
 
     env.filters["render_markdown"] = render_markdown
+    env.filters["render_date"] = render_date
 
     rsync("src/covers/", "_html/covers/")
     rsync("src/static/", "_html/static/")
 
     for review_entry in all_reviews:
-        template = env.get_template("review.html")
-        html = template.render(review_entry=review_entry)
+        render_individual_review(env, review_entry=review_entry)
+
+    template = env.get_template("list_reviews.html")
+    html = template.render(all_reviews=all_reviews)
 
-        out_name = review_entry.path.relative_to("src").with_suffix(".html")
-        out_path = pathlib.Path("_html") / out_name
-        out_path.parent.mkdir(exist_ok=True, parents=True)
-        out_path.write_text(html)
+    out_path = pathlib.Path("_html") / 'reviews/index.html'
+    out_path.write_text(html)
index 81114f1..4672f17 100644 (file)
@@ -10,12 +10,14 @@ h1 .book-title {
   line-height: 1.2em;
 }
 
-.book-cover {
+.book-cover img {
   float: right;
   max-width:  150px;
   max-height: 250px;
+  margin-top: 10px;
   margin-left: 10px;
   margin-bottom: 10px;
+  box-shadow: 0px 5px 5px rgba(0,0,0,0.25);
 }
 
 aside {
@@ -64,13 +66,13 @@ aside a:hover {
   background: rgba(255, 255, 255, 0.3);
 }
 
-table {
+table.book_metadata {
   border-collapse: collapse;
   margin-bottom: 1em;
 }
 
 td {
-  padding-right: 6px;
+  padding-right: 8px;
   padding-top:    2px;
   padding-bottom: 2px;
 }
diff --git a/templates/_book_cover.html b/templates/_book_cover.html
new file mode 100644 (file)
index 0000000..2164300
--- /dev/null
@@ -0,0 +1 @@
+<img src="/covers/{{ book.cover_image }}" alt="Cover of {{ book.title }}. {{ book.cover_desc }}">
diff --git a/templates/list_reviews.html b/templates/list_reviews.html
new file mode 100644 (file)
index 0000000..82935b9
--- /dev/null
@@ -0,0 +1,83 @@
+{% extends "base.html" %}
+
+{% block content %}
+  <h1>my reviews</h1>
+  <style>
+    .review_preview {
+      border: 3px solid #4c3dae;
+      border-radius: 6px;
+      margin-bottom: 1em;
+    }
+
+    .review_preview a {
+      grid-template-columns: 110px auto;
+      display: grid;
+      grid-gap: 15px;
+      width: 100%;
+      color: black;
+      text-decoration: none;
+    }
+
+    .review_preview img {
+      max-height: 110px;
+      border: 0.5px solid rgba(76, 61, 174, 0.6);
+      margin-top: 12px;
+      margin-bottom: 7px;
+    }
+
+    .review_preview .book_thumbnail {
+      text-align: center;
+    }
+
+    .review_preview .book_metadata {
+      grid-row: 1/1;
+      grid-column: 2/2;
+      display: inline-block;
+      margin-top:    auto;
+      margin-bottom: auto;
+      line-height: 1.25em;
+    }
+
+    .review_preview .book_metadata p.title {
+      font-style: italic;
+      font-size: 1.05em;
+      margin-bottom: 0.65em;
+    }
+
+    .review_preview .book_metadata p {
+      margin: 0;
+    }
+  </style>
+
+  {% for review_entry in all_reviews %}
+  <div class="review_preview">
+    <a href="/{{ review_entry.out_path() }}">
+      <div class="book_thumbnail">
+        {% set book = review_entry.book %}
+        {% include "_book_cover.html" %}
+      </div>
+
+      <div class="book_metadata">
+        <p class="title">{{ review_entry.book.title }}</p>
+        <p>
+          <small>
+            by {{ review_entry.book.author }}
+            {%- if review_entry.book.publication_year %}
+              ({{ review_entry.book.publication_year}})
+            {%- endif -%}
+              <br/>
+            read {{ review_entry.review.date_read | render_date }}
+              <br/>
+            {% for _ in range(review_entry.review.rating) %}
+            ★
+            {% endfor %}
+            {% for _ in range(5 - review_entry.review.rating) %}
+            ☆
+            {% endfor %}
+          </small>
+        </p>
+      </div>
+    </a>
+  </div>
+  {% endfor %}
+{% endblock %}
\ No newline at end of file
index 233e7f7..be5e0c4 100644 (file)
@@ -2,12 +2,15 @@
 
 {% block content %}
   {% if review_entry.book.cover_image %}
-  <img class="book-cover" src="/covers/{{ review_entry.book.cover_image }}" alt="Cover of {{ review_entry.book.title }}. {{ review_entry.book.cover_desc }}">
+    <div class="book-cover">
+      {% set book = review_entry.book %}
+      {% include "_book_cover.html" %}
+    </div>
   {% endif %}
 
   <h1>My review of <span class="book-title">{{ review_entry.book.title }}</span></h1>
 
-  <table>
+  <table class="book_metadata">
     <tr>
       <td>author:</td>
       <th>{{ review_entry.book.author }}
@@ -29,7 +32,7 @@
     </tr>
     <tr>
       <td>date read:</td>
-      <th>{{ review_entry.review.date_read }}</th>
+      <th>{{ review_entry.review.date_read | render_date }}</th>
     </tr>
   </table>
 
diff --git a/templates/reviews.html b/templates/reviews.html
deleted file mode 100644 (file)
index 63913c1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{% extends "base.html" %}
\ No newline at end of file