Humanize reading time
This commit is contained in:
parent
2dd660ed13
commit
710a4c7955
11 changed files with 36 additions and 27 deletions
|
@ -16,3 +16,4 @@ psycopg2
|
||||||
djangorestframework
|
djangorestframework
|
||||||
django-htmx
|
django-htmx
|
||||||
wagtail-metadata
|
wagtail-metadata
|
||||||
|
humanize
|
||||||
|
|
|
@ -28,6 +28,7 @@ draftjs-exporter==2.1.7 # via wagtail
|
||||||
et-xmlfile==1.1.0 # via openpyxl
|
et-xmlfile==1.1.0 # via openpyxl
|
||||||
gunicorn==20.1.0 # via -r requirements/base.in
|
gunicorn==20.1.0 # via -r requirements/base.in
|
||||||
html5lib==1.1 # via wagtail
|
html5lib==1.1 # via wagtail
|
||||||
|
humanize==4.3.0 # via -r requirements/base.in
|
||||||
idna==3.3 # via requests
|
idna==3.3 # via requests
|
||||||
l18n==2021.3 # via wagtail
|
l18n==2021.3 # via wagtail
|
||||||
lxml==4.9.1 # via -r requirements/base.in
|
lxml==4.9.1 # via -r requirements/base.in
|
||||||
|
|
|
@ -40,6 +40,7 @@ flake8==4.0.1 # via -r requirements/dev.in
|
||||||
gunicorn==20.1.0 # via -r requirements/base.txt
|
gunicorn==20.1.0 # via -r requirements/base.txt
|
||||||
honcho==1.1.0 # via -r requirements/dev.in
|
honcho==1.1.0 # via -r requirements/dev.in
|
||||||
html5lib==1.1 # via -r requirements/base.txt, wagtail
|
html5lib==1.1 # via -r requirements/base.txt, wagtail
|
||||||
|
humanize==4.3.0 # via -r requirements/base.txt
|
||||||
idna==3.3 # via -r requirements/base.txt, requests
|
idna==3.3 # via -r requirements/base.txt, requests
|
||||||
isort==5.10.1 # via -r requirements/dev.in
|
isort==5.10.1 # via -r requirements/dev.in
|
||||||
l18n==2021.3 # via -r requirements/base.txt, wagtail
|
l18n==2021.3 # via -r requirements/base.txt, wagtail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import math
|
from datetime import timedelta
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -68,11 +68,18 @@ class BaseContentPage(BasePage, MetadataMixin):
|
||||||
return get_table_of_contents(self.content_html)
|
return get_table_of_contents(self.content_html)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def reading_time(self) -> int:
|
def reading_time(self) -> timedelta:
|
||||||
"""
|
"""
|
||||||
https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
||||||
"""
|
"""
|
||||||
return int(math.ceil(self.word_count / 265))
|
return timedelta(seconds=(self.word_count / 265) * 60)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def show_reading_time(self) -> bool:
|
||||||
|
"""
|
||||||
|
Only show reading time if it's longer than 2 minutes
|
||||||
|
"""
|
||||||
|
return self.reading_time.total_seconds() >= 120
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def word_count(self) -> int:
|
def word_count(self) -> int:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load wagtailcore_tags %}
|
{% load wagtailcore_tags humanize_tags %}
|
||||||
|
|
||||||
<div class="content-details field is-grouped is-grouped-multiline {{extra_classes}}">
|
<div class="content-details field is-grouped is-grouped-multiline {{extra_classes}}">
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.reading_time %}
|
{% if page.show_reading_time %}
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<div class="tags has-addons">
|
<div class="tags has-addons">
|
||||||
<span class="tag is-dark"><i class="far fa-clock"></i></span>
|
<span class="tag is-dark"><i class="far fa-clock"></i></span>
|
||||||
<span class="tag is-light" title="{{ page.word_count }} words">{{ page.reading_time }} minutes</span>
|
<span class="tag is-light" title="{{ page.word_count }} words">{{ page.reading_time|naturaldelta }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
{% extends "wagtailmetadata/parts/tags.html" %}
|
{% extends "wagtailmetadata/parts/tags.html" %}
|
||||||
|
|
||||||
|
{% load humanize_tags %}
|
||||||
|
|
||||||
{% block twitter %}
|
{% block twitter %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
{% if object.reading_time %}
|
{% if object.show_reading_time %}
|
||||||
<meta name="twitter:label1" content="Reading time" />
|
<meta name="twitter:label1" content="Reading time" />
|
||||||
<meta name="twitter:data1" content="{{ object.reading_time }} minutes" />
|
<meta name="twitter:data1" content="{{ object.reading_time|naturaldelta }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,8 @@ class ContactPage(BaseContentPage):
|
||||||
subpage_types: list = []
|
subpage_types: list = []
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def reading_time(self) -> int:
|
def show_reading_time(self) -> bool:
|
||||||
"""
|
return False
|
||||||
How does one read a list page?
|
|
||||||
"""
|
|
||||||
return 0
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def table_of_contents(self) -> list[TocEntry]:
|
def table_of_contents(self) -> list[TocEntry]:
|
||||||
|
|
|
@ -24,11 +24,8 @@ class SearchPage(RoutablePageMixin, BaseContentPage):
|
||||||
PAGE_SIZE = 15
|
PAGE_SIZE = 15
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def reading_time(self) -> int:
|
def show_reading_time(self) -> bool:
|
||||||
"""
|
return False
|
||||||
How does one read a search page?
|
|
||||||
"""
|
|
||||||
return 0
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def table_of_contents(self) -> list[TocEntry]:
|
def table_of_contents(self) -> list[TocEntry]:
|
||||||
|
|
|
@ -33,6 +33,7 @@ INSTALLED_APPS = [
|
||||||
"website.images",
|
"website.images",
|
||||||
"website.contact",
|
"website.contact",
|
||||||
"website.spotify",
|
"website.spotify",
|
||||||
|
"website.utils",
|
||||||
"website.contrib.code_block",
|
"website.contrib.code_block",
|
||||||
"website.contrib.mermaid_block",
|
"website.contrib.mermaid_block",
|
||||||
"website.contrib.unsplash",
|
"website.contrib.unsplash",
|
||||||
|
|
|
@ -35,15 +35,11 @@ class SpotifyPlaylistPage(BaseContentPage):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def reading_time(self) -> int:
|
def reading_time(self) -> timedelta:
|
||||||
return int(
|
return timedelta(
|
||||||
timedelta(
|
|
||||||
milliseconds=sum(
|
milliseconds=sum(
|
||||||
track["track"]["duration_ms"]
|
track["track"]["duration_ms"] for track in self.playlist_data["tracks"]
|
||||||
for track in self.playlist_data["tracks"]
|
|
||||||
)
|
)
|
||||||
).total_seconds()
|
|
||||||
/ 60
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
|
6
website/utils/templatetags/humanize_tags.py
Normal file
6
website/utils/templatetags/humanize_tags.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import humanize
|
||||||
|
from django.template import Library
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
register.filter(humanize.naturaldelta)
|
Loading…
Reference in a new issue