feat: sitemap
feat: reading time
This commit is contained in:
parent
ee400e076f
commit
97f9079fef
@ -8,6 +8,8 @@ twitter_username: mdibaiee
|
|||||||
github_username: mdibaiee
|
github_username: mdibaiee
|
||||||
repo: "https://github.com/mdibaiee/theread.me"
|
repo: "https://github.com/mdibaiee/theread.me"
|
||||||
|
|
||||||
|
date_format: "%b %d, %Y"
|
||||||
|
|
||||||
# Build settings
|
# Build settings
|
||||||
markdown: kramdown
|
markdown: kramdown
|
||||||
permalink: /:title/
|
permalink: /:title/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="share-page">
|
<div class="share-page">
|
||||||
Share this →
|
Share in
|
||||||
|
|
||||||
<a href="https://twitter.com/intent/tweet?text={{ page.title }}&url={{ site.url }}{{ page.url }}&via={{ site.twitter_username }}&related={{ site.twitter_username }}" rel="nofollow" target="_blank" title="Share on Twitter">Twitter</a>
|
<a href="https://twitter.com/intent/tweet?text={{ page.title }}&url={{ site.url }}{{ page.url }}&via={{ site.twitter_username }}&related={{ site.twitter_username }}" rel="nofollow" target="_blank" title="Share on Twitter">Twitter</a>
|
||||||
<a href="https://facebook.com/sharer.php?u={{ site.url }}{{ page.url }}" rel="nofollow" target="_blank" title="Share on Facebook">Facebook</a>
|
<a href="https://facebook.com/sharer.php?u={{ site.url }}{{ page.url }}" rel="nofollow" target="_blank" title="Share on Facebook">Facebook</a>
|
||||||
|
@ -5,7 +5,12 @@ layout: default
|
|||||||
|
|
||||||
<div class="post-header">
|
<div class="post-header">
|
||||||
<h1 class="post-title">{{ page.title }}</h1>
|
<h1 class="post-title">{{ page.title }}</h1>
|
||||||
<p class="post-meta">{{ page.date | date: "%b %-d, %Y" }}{% if page.author %} • {{ page.author }}{% endif %}{% if page.meta %} • {{ page.meta }}{% endif %}</p>
|
<p class="post-meta">
|
||||||
|
<span>{{ page.date | date: "%b %-d, %Y" }}</span>
|
||||||
|
{% if page.author %} • <span>{{ page.author }}</span>{% endif %}
|
||||||
|
{% if page.meta %} • <span>{{ page.meta }}</span>{% endif %}
|
||||||
|
• <span>Reading time: {{ content | reading_time }}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<article class="post-content">
|
<article class="post-content">
|
||||||
|
18
_plugins/reading_time.rb
Normal file
18
_plugins/reading_time.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Outputs the reading time
|
||||||
|
|
||||||
|
# Read this in “about 4 minutes”
|
||||||
|
# Put into your _plugins dir in your Jekyll site
|
||||||
|
# Usage: Read this in about {{ page.content | reading_time }}
|
||||||
|
|
||||||
|
module ReadingTimeFilter
|
||||||
|
def reading_time( input )
|
||||||
|
words_per_minute = 180
|
||||||
|
|
||||||
|
words = input.split.size;
|
||||||
|
minutes = ( words / words_per_minute ).floor
|
||||||
|
minutes_label = minutes === 1 ? " minute" : " minutes"
|
||||||
|
minutes > 0 ? "#{minutes} #{minutes_label}" : "less than 1 minute"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Liquid::Template.register_filter(ReadingTimeFilter)
|
274
_plugins/sitemap.rb
Normal file
274
_plugins/sitemap.rb
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
# Sitemap.xml Generator is a Jekyll plugin that generates a sitemap.xml file by
|
||||||
|
# traversing all of the available posts and pages.
|
||||||
|
#
|
||||||
|
# See readme file for documenation
|
||||||
|
#
|
||||||
|
# Updated to use config file for settings by Daniel Groves
|
||||||
|
# Site: http://danielgroves.net
|
||||||
|
#
|
||||||
|
# Author: Michael Levin
|
||||||
|
# Site: http://www.kinnetica.com
|
||||||
|
# Distributed Under A Creative Commons License
|
||||||
|
# - http://creativecommons.org/licenses/by/3.0/
|
||||||
|
require 'jekyll/document'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
module Jekyll
|
||||||
|
|
||||||
|
class Jekyll::Document
|
||||||
|
attr_accessor :name
|
||||||
|
|
||||||
|
def path_to_source
|
||||||
|
File.join(*[@name].compact)
|
||||||
|
end
|
||||||
|
|
||||||
|
def location_on_server(my_url)
|
||||||
|
"#{my_url}#{url}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Page
|
||||||
|
attr_accessor :name
|
||||||
|
|
||||||
|
def path_to_source
|
||||||
|
File.join(*[@dir, @name].compact)
|
||||||
|
end
|
||||||
|
|
||||||
|
def location_on_server(my_url)
|
||||||
|
location = "#{my_url}#{url}"
|
||||||
|
location.gsub(/index.html$/, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Recover from strange exception when starting server without --auto
|
||||||
|
class SitemapFile < StaticFile
|
||||||
|
def write(dest)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SitemapGenerator < Generator
|
||||||
|
priority :lowest
|
||||||
|
|
||||||
|
# Config defaults
|
||||||
|
SITEMAP_FILE_NAME = "/sitemap.xml"
|
||||||
|
EXCLUDE = ["/atom.xml", "/feed.xml", "/feed/index.xml"]
|
||||||
|
INCLUDE_POSTS = ["/index.html"]
|
||||||
|
CHANGE_FREQUENCY_NAME = "change_frequency"
|
||||||
|
PRIORITY_NAME = "priority"
|
||||||
|
|
||||||
|
# Valid values allowed by sitemap.xml spec for change frequencies
|
||||||
|
VALID_CHANGE_FREQUENCY_VALUES = ["always", "hourly", "daily", "weekly",
|
||||||
|
"monthly", "yearly", "never"]
|
||||||
|
|
||||||
|
# Goes through pages and posts and generates sitemap.xml file
|
||||||
|
#
|
||||||
|
# Returns nothing
|
||||||
|
def generate(site)
|
||||||
|
# Configuration
|
||||||
|
sitemap_config = site.config['sitemap'] || {}
|
||||||
|
@config = {}
|
||||||
|
@config['filename'] = sitemap_config['filename'] || SITEMAP_FILE_NAME
|
||||||
|
@config['change_frequency_name'] = sitemap_config['change_frequency_name'] || CHANGE_FREQUENCY_NAME
|
||||||
|
@config['priority_name'] = sitemap_config['priority_name'] || PRIORITY_NAME
|
||||||
|
@config['exclude'] = sitemap_config['exclude'] || EXCLUDE
|
||||||
|
@config['include_posts'] = sitemap_config['include_posts'] || INCLUDE_POSTS
|
||||||
|
|
||||||
|
sitemap = REXML::Document.new << REXML::XMLDecl.new("1.0", "UTF-8")
|
||||||
|
|
||||||
|
urlset = REXML::Element.new "urlset"
|
||||||
|
urlset.add_attribute("xmlns",
|
||||||
|
"http://www.sitemaps.org/schemas/sitemap/0.9")
|
||||||
|
|
||||||
|
@last_modified_post_date = fill_posts(site, urlset)
|
||||||
|
fill_pages(site, urlset)
|
||||||
|
|
||||||
|
sitemap.add_element(urlset)
|
||||||
|
|
||||||
|
# Create destination directory if it doesn't exist yet. Otherwise, we cannot write our file there.
|
||||||
|
Dir::mkdir(site.dest) if !File.directory? site.dest
|
||||||
|
|
||||||
|
# File I/O: create sitemap.xml file and write out pretty-printed XML
|
||||||
|
filename = @config['filename']
|
||||||
|
file = File.new(File.join(site.dest, filename), "w")
|
||||||
|
formatter = REXML::Formatters::Pretty.new(4)
|
||||||
|
formatter.compact = true
|
||||||
|
formatter.write(sitemap, file)
|
||||||
|
file.close
|
||||||
|
|
||||||
|
# Keep the sitemap.xml file from being cleaned by Jekyll
|
||||||
|
site.static_files << Jekyll::SitemapFile.new(site, site.dest, "/", filename)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create url elements for all the posts and find the date of the latest one
|
||||||
|
#
|
||||||
|
# Returns last_modified_date of latest post
|
||||||
|
def fill_posts(site, urlset)
|
||||||
|
|
||||||
|
last_modified_date = nil
|
||||||
|
site.collections["posts"].docs.each do |post|
|
||||||
|
if !excluded?(site, post.name)
|
||||||
|
url = fill_url(site, post)
|
||||||
|
urlset.add_element(url)
|
||||||
|
end
|
||||||
|
|
||||||
|
date = File.mtime(post.path)
|
||||||
|
last_modified_date = date if last_modified_date == nil or date > last_modified_date
|
||||||
|
end
|
||||||
|
|
||||||
|
last_modified_date
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create url elements for all the normal pages and find the date of the
|
||||||
|
# index to use with the pagination pages
|
||||||
|
#
|
||||||
|
# Returns last_modified_date of index page
|
||||||
|
def fill_pages(site, urlset)
|
||||||
|
site.pages.each do |page|
|
||||||
|
if !excluded?(site, page.path_to_source)
|
||||||
|
if File.exists?(page.path)
|
||||||
|
url = fill_url(site, page)
|
||||||
|
urlset.add_element(url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Fill data of each URL element: location, last modified,
|
||||||
|
# change frequency (optional), and priority.
|
||||||
|
#
|
||||||
|
# Returns url REXML::Element
|
||||||
|
def fill_url(site, page_or_post)
|
||||||
|
url = REXML::Element.new "url"
|
||||||
|
|
||||||
|
loc = fill_location(site, page_or_post)
|
||||||
|
url.add_element(loc)
|
||||||
|
|
||||||
|
lastmod = fill_last_modified(site, page_or_post)
|
||||||
|
url.add_element(lastmod) if lastmod
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (page_or_post.data[@config['change_frequency_name']])
|
||||||
|
change_frequency =
|
||||||
|
page_or_post.data[@config['change_frequency_name']].downcase
|
||||||
|
|
||||||
|
if (valid_change_frequency?(change_frequency))
|
||||||
|
changefreq = REXML::Element.new "changefreq"
|
||||||
|
changefreq.text = change_frequency
|
||||||
|
url.add_element(changefreq)
|
||||||
|
else
|
||||||
|
puts "ERROR: Invalid Change Frequency In #{page_or_post.name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (page_or_post.data[@config['priority_name']])
|
||||||
|
priority_value = page_or_post.data[@config['priority_name']]
|
||||||
|
if valid_priority?(priority_value)
|
||||||
|
priority = REXML::Element.new "priority"
|
||||||
|
priority.text = page_or_post.data[@config['priority_name']]
|
||||||
|
url.add_element(priority)
|
||||||
|
else
|
||||||
|
puts "ERROR: Invalid Priority In #{page_or_post.name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
url
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get URL location of page or post
|
||||||
|
#
|
||||||
|
# Returns the location of the page or post
|
||||||
|
def fill_location(site, page_or_post)
|
||||||
|
loc = REXML::Element.new "loc"
|
||||||
|
url = site.config['url'] + site.config['baseurl']
|
||||||
|
loc.text = page_or_post.location_on_server(url)
|
||||||
|
|
||||||
|
loc
|
||||||
|
end
|
||||||
|
|
||||||
|
# Fill lastmod XML element with the last modified date for the page or post.
|
||||||
|
#
|
||||||
|
# Returns lastmod REXML::Element or nil
|
||||||
|
def fill_last_modified(site, page_or_post)
|
||||||
|
lastmod = REXML::Element.new "lastmod"
|
||||||
|
date = File.mtime(page_or_post.path)
|
||||||
|
latest_date = find_latest_date(date, site, page_or_post)
|
||||||
|
|
||||||
|
if @last_modified_post_date == nil
|
||||||
|
# This is a post
|
||||||
|
lastmod.text = latest_date.iso8601
|
||||||
|
else
|
||||||
|
# This is a page
|
||||||
|
if posts_included?(site, page_or_post.path_to_source)
|
||||||
|
# We want to take into account the last post date
|
||||||
|
final_date = greater_date(latest_date, @last_modified_post_date)
|
||||||
|
lastmod.text = final_date.iso8601
|
||||||
|
else
|
||||||
|
lastmod.text = latest_date.iso8601
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lastmod
|
||||||
|
end
|
||||||
|
|
||||||
|
# Go through the page/post and any implemented layouts and get the latest
|
||||||
|
# modified date
|
||||||
|
#
|
||||||
|
# Returns formatted output of latest date of page/post and any used layouts
|
||||||
|
def find_latest_date(latest_date, site, page_or_post)
|
||||||
|
layouts = site.layouts
|
||||||
|
layout = layouts[page_or_post.data["layout"]]
|
||||||
|
while layout
|
||||||
|
date = File.mtime(layout.path)
|
||||||
|
|
||||||
|
latest_date = date if (date > latest_date)
|
||||||
|
|
||||||
|
layout = layouts[layout.data["layout"]]
|
||||||
|
end
|
||||||
|
|
||||||
|
latest_date
|
||||||
|
end
|
||||||
|
|
||||||
|
# Which of the two dates is later
|
||||||
|
#
|
||||||
|
# Returns latest of two dates
|
||||||
|
def greater_date(date1, date2)
|
||||||
|
if (date1 >= date2)
|
||||||
|
date1
|
||||||
|
else
|
||||||
|
date2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Is the page or post listed as something we want to exclude?
|
||||||
|
#
|
||||||
|
# Returns boolean
|
||||||
|
def excluded?(site, name)
|
||||||
|
@config['exclude'].include? name
|
||||||
|
end
|
||||||
|
|
||||||
|
def posts_included?(site, name)
|
||||||
|
@config['include_posts'].include? name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Is the change frequency value provided valid according to the spec
|
||||||
|
#
|
||||||
|
# Returns boolean
|
||||||
|
def valid_change_frequency?(change_frequency)
|
||||||
|
VALID_CHANGE_FREQUENCY_VALUES.include? change_frequency
|
||||||
|
end
|
||||||
|
|
||||||
|
# Is the priority value provided valid according to the spec
|
||||||
|
#
|
||||||
|
# Returns boolean
|
||||||
|
def valid_priority?(priority)
|
||||||
|
begin
|
||||||
|
priority_val = Float(priority)
|
||||||
|
return true if priority_val >= 0.0 and priority_val <= 1.0
|
||||||
|
rescue ArgumentError
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -9,6 +9,10 @@ body {
|
|||||||
background: rgba(0, 0, 0, 0.1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin: 50px 0;
|
margin: 50px 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
@ -67,11 +71,17 @@ header {
|
|||||||
h2, h1 {
|
h2, h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-meta {
|
.post-meta {
|
||||||
font-size: $small-font-size;
|
font-size: $small-font-size;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 1rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,13 @@ layout: default
|
|||||||
<li>
|
<li>
|
||||||
<h2>
|
<h2>
|
||||||
<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
|
<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
|
||||||
<span class="post-meta">{{ post.date | date: "%b %-d, %Y" }}</span>
|
|
||||||
|
<p class="post-meta">
|
||||||
|
<span>{{ post.date | date: "%b %-d, %Y" }}</span>
|
||||||
|
{% if post.author %} • <span>{{ post.author }}</span>{% endif %}
|
||||||
|
{% if post.meta %} • <span>{{ post.meta }}</span>{% endif %}
|
||||||
|
• <span>Reading time: {{ post.content | reading_time }}</span>
|
||||||
|
</p>
|
||||||
</h2>
|
</h2>
|
||||||
<article class='post-content'>
|
<article class='post-content'>
|
||||||
{{ post.excerpt }}
|
{{ post.excerpt }}
|
||||||
|
Loading…
Reference in New Issue
Block a user