Support formats; add a "currently reading" page
authorAlex Chan <alex@alexwlchan.net>
Sun, 2 Feb 2020 19:39:49 +0000 (19:39 +0000)
committerAlex Chan <alex@alexwlchan.net>
Sun, 2 Feb 2020 19:39:49 +0000 (19:39 +0000)
scripts/add_book.py
scripts/render_html.py
src/covers/how-to-understand-your-gender.jpg [new file with mode: 0644]
src/currently_reading/how-to-understand-your-gender.md [new file with mode: 0644]
src/index.md
src/reviews/2020/the-ones-who-walk-away-from-omelas.md
src/reviews/2020/trans-like-me.md
src/reviews/2020/why-buildings-fall-down.md
static/style.css
templates/list_reading.html [new file with mode: 0644]
templates/list_reviews.html

index df75786..2cf6da7 100755 (executable)
@@ -14,11 +14,11 @@ from unidecode import unidecode
 def slugify(u):
     """Convert Unicode string into blog slug."""
     # https://leancrew.com/all-this/2014/10/asciifying/
 def slugify(u):
     """Convert Unicode string into blog slug."""
     # https://leancrew.com/all-this/2014/10/asciifying/
-    u = re.sub(u'[–—/:;,.]', '-', u)  # replace separating punctuation
-    a = unidecode(u).lower()          # best ASCII substitutions, lowercased
-    a = re.sub(r'[^a-z0-9 -]', '', a) # delete any other characters
-    a = a.replace(' ', '-')           # spaces to hyphens
-    a = re.sub(r'-+', '-', a)         # condense repeated hyphens
+    u = re.sub("[–—/:;,.]", "-", u)  # replace separating punctuation
+    a = unidecode(u).lower()  # best ASCII substitutions, lowercased
+    a = re.sub(r"[^a-z0-9 -]", "", a)  # delete any other characters
+    a = a.replace(" ", "-")  # spaces to hyphens
+    a = re.sub(r"-+", "-", a)  # condense repeated hyphens
     return a
 
 
     return a
 
 
@@ -58,7 +58,7 @@ def get_review_info():
         inquirer.List(
             "date_read",
             message="When did you finish reading it?",
         inquirer.List(
             "date_read",
             message="When did you finish reading it?",
-            choices=["today", "yesterday", "another day"]
+            choices=["today", "yesterday", "another day"],
         )
     ]
 
         )
     ]
 
@@ -73,29 +73,27 @@ def get_review_info():
         date_read = yesterday.strftime("%Y-%m-%d")
     else:
         date_read_question2 = [
         date_read = yesterday.strftime("%Y-%m-%d")
     else:
         date_read_question2 = [
-            inquirer.Text(
-                "date_read",
-                message="When did you finish reading it?"
-            )
+            inquirer.Text("date_read", message="When did you finish reading it?")
         ]
 
         date_read = inquirer.prompt(date_read_question2)["date_read"]
 
         ]
 
         date_read = inquirer.prompt(date_read_question2)["date_read"]
 
-    rating_question = [
+    other_questions = [
         inquirer.List(
             "rating",
             message="When’s your rating?",
         inquirer.List(
             "rating",
             message="When’s your rating?",
-            choices=["★★★★★", "★★★★☆", "★★★☆☆", "★★☆☆☆", "★☆☆☆☆"]
-        )
+            choices=["★★★★★", "★★★★☆", "★★★☆☆", "★★☆☆☆", "★☆☆☆☆"],
+        ),
+        inquirer.Text("format", message="What format did you read it in?"),
     ]
 
     ]
 
-    rating = int(inquirer.prompt(rating_question)["rating"].count("★"))
-
-    return {"date_read": date_read, "rating": rating}
+    answers = inquirer.prompt(other_questions)
+    rating = int(["rating"].count("★"))
 
 
+    return {"date_read": date_read, "rating": rating, "format": answers["format"]}
 
 
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     book_info = get_book_info()
 
     slug = slugify(book_info["title"])
     book_info = get_book_info()
 
     slug = slugify(book_info["title"])
@@ -123,7 +121,8 @@ if __name__ == '__main__':
 
         new_entry["review"] = {
             "date_read": review_info["date_read"],
 
         new_entry["review"] = {
             "date_read": review_info["date_read"],
-            "rating": review_info["rating"]
+            "rating": review_info["rating"],
+            "format": review_info["format"],
         }
 
         year = review_info["date_read"][:4]
         }
 
         year = review_info["date_read"][:4]
@@ -135,7 +134,7 @@ if __name__ == '__main__':
     os.makedirs(os.path.dirname(out_path), exist_ok=True)
 
     with open(out_path, "wb") as out_file:
     os.makedirs(os.path.dirname(out_path), exist_ok=True)
 
     with open(out_path, "wb") as out_file:
-        frontmatter.dump(frontmatter.Post(content=u"", **new_entry), out_file)
+        frontmatter.dump(frontmatter.Post(content="", **new_entry), out_file)
         out_file.write(b"\n")
 
     subprocess.check_call(["open", out_path])
         out_file.write(b"\n")
 
     subprocess.check_call(["open", out_path])
index 670754e..bb0eb11 100755 (executable)
@@ -26,7 +26,8 @@ class Book:
     cover_image = attr.ib()
     cover_desc = attr.ib(default="")
 
     cover_image = attr.ib()
     cover_desc = attr.ib(default="")
 
-    isbn_13 = attr.ib(default="")
+    isbn10 = attr.ib(default="")
+    isbn13 = attr.ib(default="")
 
 
 @attr.s
 
 
 @attr.s
@@ -34,6 +35,7 @@ class Review:
     date_read = attr.ib()
     rating = attr.ib()
     text = attr.ib()
     date_read = attr.ib()
     rating = attr.ib()
     text = attr.ib()
+    format = attr.ib()
 
 
 @attr.s
 
 
 @attr.s
@@ -55,8 +57,32 @@ def get_review_entry_from_path(path):
     return ReviewEntry(path=path, book=book, review=review)
 
 
     return ReviewEntry(path=path, book=book, review=review)
 
 
-def get_reviews():
-    for dirpath, _, filenames in os.walk("src/reviews"):
+@attr.s
+class CurrentlyReading:
+    text = attr.ib()
+
+
+@attr.s
+class CurrentlyReadingEntry:
+    path = attr.ib()
+    book = attr.ib()
+    reading = attr.ib()
+
+    def out_path(self):
+        return self.path.relative_to("src").with_suffix("")
+
+
+def get_reading_entry_from_path(path):
+    post = frontmatter.load(path)
+
+    book = Book(**post["book"])
+    reading = CurrentlyReading(text=post.content)
+
+    return CurrentlyReadingEntry(path=path, book=book, reading=reading)
+
+
+def get_reviews(dirpath, constructor):
+    for dirpath, _, filenames in os.walk(dirpath):
         for f in filenames:
             if not f.endswith(".md"):
                 continue
         for f in filenames:
             if not f.endswith(".md"):
                 continue
@@ -64,7 +90,7 @@ def get_reviews():
             path = pathlib.Path(dirpath) / f
 
             try:
             path = pathlib.Path(dirpath) / f
 
             try:
-                yield get_review_entry_from_path(path)
+                yield constructor(path)
             except Exception:
                 print(f"Error parsing {path}", file=sys.stderr)
                 raise
             except Exception:
                 print(f"Error parsing {path}", file=sys.stderr)
                 raise
@@ -106,11 +132,6 @@ def render_individual_review(env, *, review_entry):
 
 
 if __name__ == "__main__":
 
 
 if __name__ == "__main__":
-    all_reviews = list(get_reviews())
-    all_reviews = sorted(
-        all_reviews, key=lambda rev: str(rev.review.date_read), reverse=True
-    )
-
     env = Environment(
         loader=FileSystemLoader("templates"),
         autoescape=select_autoescape(["html", "xml"]),
     env = Environment(
         loader=FileSystemLoader("templates"),
         autoescape=select_autoescape(["html", "xml"]),
@@ -122,6 +143,15 @@ if __name__ == "__main__":
     rsync("src/covers/", "_html/covers/")
     rsync("static/", "_html/static/")
 
     rsync("src/covers/", "_html/covers/")
     rsync("static/", "_html/static/")
 
+    # Render the "all reviews page"
+
+    all_reviews = list(
+        get_reviews(dirpath="src/reviews", constructor=get_review_entry_from_path)
+    )
+    all_reviews = sorted(
+        all_reviews, key=lambda rev: str(rev.review.date_read), reverse=True
+    )
+
     for review_entry in all_reviews:
         render_individual_review(env, review_entry=review_entry)
 
     for review_entry in all_reviews:
         render_individual_review(env, review_entry=review_entry)
 
@@ -131,6 +161,19 @@ if __name__ == "__main__":
     out_path = pathlib.Path("_html") / "reviews/index.html"
     out_path.write_text(html)
 
     out_path = pathlib.Path("_html") / "reviews/index.html"
     out_path.write_text(html)
 
+    # Render the "currently reading" page
+
+    all_reading = list(
+        get_reviews(dirpath="src/currently_reading", constructor=get_reading_entry_from_path)
+    )
+
+    template = env.get_template("list_reading.html")
+    html = template.render(all_reading=all_reading)
+
+    out_path = pathlib.Path("_html") / "reading/index.html"
+    out_path.parent.mkdir(exist_ok=True, parents=True)
+    out_path.write_text(html)
+
     # Render the front page
 
     index_template = env.get_template("index.html")
     # Render the front page
 
     index_template = env.get_template("index.html")
diff --git a/src/covers/how-to-understand-your-gender.jpg b/src/covers/how-to-understand-your-gender.jpg
new file mode 100644 (file)
index 0000000..2b11885
Binary files /dev/null and b/src/covers/how-to-understand-your-gender.jpg differ
diff --git a/src/currently_reading/how-to-understand-your-gender.md b/src/currently_reading/how-to-understand-your-gender.md
new file mode 100644 (file)
index 0000000..0791ac2
--- /dev/null
@@ -0,0 +1,12 @@
+---
+book:
+  author: Alex Iantaffi and Meg-John Barker
+  cover_image: how-to-understand-your-gender.jpg
+  isbn13: '9781785927461'
+  publication_year: '2018'
+  title: How to Understand Your Gender
+---
+
+I've borrowed a copy from David MacIver, which he lent me a while back when I was figuring out more gender stuff.
+
+The recommendation from him and Alex is to skim it for interesting, but I may not need to read it all in detail.
index fdb8e75..4c7636f 100644 (file)
@@ -3,7 +3,7 @@
 This is a small app I created to track the books I’m reading. In this app, I can:
 
 *   Write mini-reviews of the [books I’ve read](/reviews/)
 This is a small app I created to track the books I’m reading. In this app, I can:
 
 *   Write mini-reviews of the [books I’ve read](/reviews/)
-*   Keep track of what I’m [currently reading](/currently-reading/)
+*   Keep track of what I’m [currently reading](/reading/)
 *   Write down what books [I want to read](/plans/), and why I want to read them
 
 This was inspired by a [similar book tracker](http://tessa-books.glitch.me/) created by [Tessa Thornton](https://twitter.com/tessthornton).
 *   Write down what books [I want to read](/plans/), and why I want to read them
 
 This was inspired by a [similar book tracker](http://tessa-books.glitch.me/) created by [Tessa Thornton](https://twitter.com/tessthornton).
index c7e6840..afdbc40 100644 (file)
@@ -7,4 +7,5 @@ book:
 review:
   date_read: '2020-02-02'
   rating: 3
 review:
   date_read: '2020-02-02'
   rating: 3
+  format: ebook
 ---
\ No newline at end of file
 ---
\ No newline at end of file
index 215d17c..cd14524 100644 (file)
@@ -7,11 +7,12 @@ book:
   cover_desc: >
     The words “trans like me” in lowercased, large letters, set on a slightly off-white background.
     The words “trans” and “me” are in red; the word “like” is in black.
   cover_desc: >
     The words “trans like me” in lowercased, large letters, set on a slightly off-white background.
     The words “trans” and “me” are in red; the word “like” is in black.
-  isbn_13: 9780349008608
+  isbn13: 9780349008608
 
 review:
   date_read: 2020-01-27
   rating: 5
 
 review:
   date_read: 2020-01-27
   rating: 5
+  format: paperback
 ---
 
 I put off reading this for ages, but I’m glad I finally got to reading it.
 ---
 
 I put off reading this for ages, but I’m glad I finally got to reading it.
index 5a84785..4f3fe95 100644 (file)
@@ -11,6 +11,7 @@ book:
 review:
   date_read: 2020-01-25
   rating: 4
 review:
   date_read: 2020-01-25
   rating: 4
+  format: paperbook
 
 ---
 
 
 ---
 
index b6a80e4..8ad798c 100644 (file)
@@ -102,14 +102,14 @@ footer a:hover {
   background: rgba(128, 128, 128, 0.3);
 }
 
   background: rgba(128, 128, 128, 0.3);
 }
 
-.review_preview {
+.review_preview, .reading {
   border: 2px solid #00a892;
   background: rgba(0, 255, 221, 0.05);
   border-radius: 6px;
   margin-bottom: 1em;
 }
 
   border: 2px solid #00a892;
   background: rgba(0, 255, 221, 0.05);
   border-radius: 6px;
   margin-bottom: 1em;
 }
 
-.review_preview a {
+.review_preview a, .reading_inner {
   grid-template-columns: 110px auto;
   display: grid;
   grid-gap: 15px;
   grid-template-columns: 110px auto;
   display: grid;
   grid-gap: 15px;
@@ -122,18 +122,18 @@ footer a:hover {
   background: rgba(0, 255, 221, 0.2);
 }
 
   background: rgba(0, 255, 221, 0.2);
 }
 
-.review_preview img {
+.review_preview img, .reading_inner img {
   max-height: 110px;
   max-height: 110px;
-  border: 0.5px solid rgba(0, 255, 221, 0.6);
   margin-top: 12px;
   margin-bottom: 7px;
   margin-top: 12px;
   margin-bottom: 7px;
+  box-shadow: 0px 2.5px 2.5px rgba(0,0,0,0.25);
 }
 
 }
 
-.review_preview .book_thumbnail {
+.book_thumbnail {
   text-align: center;
 }
 
   text-align: center;
 }
 
-.review_preview .book_metadata {
+.book_metadata {
   grid-row: 1/1;
   grid-column: 2/2;
   display: inline-block;
   grid-row: 1/1;
   grid-column: 2/2;
   display: inline-block;
@@ -142,13 +142,13 @@ footer a:hover {
   line-height: 1.25em;
 }
 
   line-height: 1.25em;
 }
 
-.review_preview .book_metadata p.title {
+.book_metadata p.title {
   font-style: italic;
   font-size: 1.15em;
   margin-bottom: 0.65em;
 }
 
   font-style: italic;
   font-size: 1.15em;
   margin-bottom: 0.65em;
 }
 
-.review_preview .book_metadata p {
+.book_metadata p {
   margin: 0;
 }
 
   margin: 0;
 }
 
@@ -159,3 +159,16 @@ footer a:hover {
 .nav .selected {
   font-weight: bold;
 }
 .nav .selected {
   font-weight: bold;
 }
+
+.note {
+  margin-left:  1em;
+  margin-right: 1em;
+}
+
+.note p:first-child {
+  margin-top: 0;
+}
+
+.note p:last-child {
+  margin-bottom: 0.75em;
+}
diff --git a/templates/list_reading.html b/templates/list_reading.html
new file mode 100644 (file)
index 0000000..ba77e50
--- /dev/null
@@ -0,0 +1,39 @@
+{% extends "base.html" %}
+
+{% block content %}
+  <p class="nav">
+    <a href="/reviews">read</a> /
+    <a class="selected" href="/reading">reading</a> /
+    <a href="/plans">to read</a>
+  </p>
+
+  <h2>books i&rsquo;m currently reading</h2>
+
+  {% for reading_entry in all_reading %}
+  <div class="reading">
+    <div class="reading_inner">
+      <div class="book_thumbnail">
+        {% set book = reading_entry.book %}
+        {% include "_book_cover.html" %}
+      </div>
+
+      <div class="book_metadata">
+        <p class="title">{{ reading_entry.book.title }}</p>
+        <p>
+          <small>
+            by {{ reading_entry.book.author }}
+            {%- if reading_entry.book.publication_year %}
+              ({{ reading_entry.book.publication_year}})
+            {%- endif -%}
+          </small>
+        </p>
+      </div>
+    </div>
+    {% if reading_entry.reading.text %}
+    <div class="note">
+      {{ reading_entry.reading.text | render_markdown | safe }}
+    </div>
+    {% endif %}
+  </div>
+  {% endfor %}
+{% endblock %}
\ No newline at end of file
index 2dfe90b..df27833 100644 (file)
@@ -2,7 +2,9 @@
 
 {% block content %}
   <p class="nav">
 
 {% block content %}
   <p class="nav">
-    <a class="selected" href="/reviews">read</a> / <a href="/currently-reading">reading</a> / <a href="/plans">to read</a>
+    <a class="selected" href="/reviews">read</a> /
+    <a href="/reading">reading</a> /
+    <a href="/plans">to read</a>
   </p>
 
   <h2>books i&rsquo;ve read</h2>
   </p>
 
   <h2>books i&rsquo;ve read</h2>