diff --git a/cmd/sorg-build/main.go b/cmd/sorg-build/main.go
index 84e5edb11..e6e4c364d 100644
--- a/cmd/sorg-build/main.go
+++ b/cmd/sorg-build/main.go
@@ -57,9 +57,9 @@ type Article struct {
// Hook is a leading sentence or two to succinctly introduce the article.
Hook string `yaml:"hook"`
- // HookImage is a boolean indicating whether there's a preview image for
- // the article that can be shown on the index page.
- HookImage bool `yaml:"hook_image"`
+ // HookImageURL is the URL for a hook image for the article (to be shown on
+ // the article index) if one was found.
+ HookImageURL string `yaml:"-"`
// Image is an optional image that may be included with an article.
Image string `yaml:"image"`
@@ -81,10 +81,6 @@ type Article struct {
// included as YAML frontmatter, but rather calculated from the article's
// content, rendered, and then added separately.
TOC string `yaml:"-"`
-
- // TwitterImage is a boolean indicating whether there's an image for
- // the article that can be shown in a Twitter card.
- TwitterImage bool `yaml:"twitter_image"`
}
// PublishingInfo produces a brief spiel about publication which is intended to
@@ -193,10 +189,6 @@ type Fragment struct {
// Title is the fragment's title.
Title string `yaml:"title"`
-
- // TwitterImage is a boolean indicating whether there's an image for
- // the article that can be shown in a Twitter card.
- TwitterImage bool `yaml:"twitter_image"`
}
// PublishingInfo produces a brief spiel about publication which is intended to
@@ -583,12 +575,26 @@ func compileArticle(dir, name string, draft bool) (*Article, error) {
return nil, err
}
+ format, ok := pathAsImage(
+ path.Join(sorg.ContentDir, "images", article.Slug, "hook"),
+ )
+ if ok {
+ article.HookImageURL = "/assets/" + article.Slug + "/hook." + format
+ }
+
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
+ }
+
card := &twitterCard{
Title: article.Title,
Description: article.Hook,
}
- if article.TwitterImage {
- card.ImageURL = sorg.AbsoluteURL + "/assets/" + article.Slug + "/twitter@2x.jpg"
+ format, ok = pathAsImage(
+ path.Join(sorg.ContentDir, "images", article.Slug, "twitter@2x"),
+ )
+ if ok {
+ card.ImageURL = sorg.AbsoluteURL + "/assets/" + article.Slug + "/twitter@2x." + format
}
locals := getLocals(article.Title, map[string]interface{}{
@@ -710,14 +716,15 @@ func compileFragment(dir, name string, draft bool) (*Fragment, error) {
// A lot of fragments still have unwritten hooks, so only add a card where
// a fragment has a configured Twitter image for the time being.
var card *twitterCard
- if fragment.TwitterImage {
+ format, ok := pathAsImage(
+ path.Join(sorg.ContentDir, "fragments", fragment.Slug, "twitter@2x"),
+ )
+ if ok {
card = &twitterCard{
+ ImageURL: "/assets/fragments/" + fragment.Slug + "/twitter@2x." + format,
Title: fragment.Title,
Description: fragment.Hook,
}
- if fragment.TwitterImage {
- card.ImageURL = sorg.AbsoluteURL + "/assets/fragments/" + fragment.Slug + "/twitter@2x.jpg"
- }
}
locals := getLocals(fragment.Title, map[string]interface{}{
@@ -2113,6 +2120,25 @@ create:
return os.Symlink(source, dest)
}
+// Checks if the path exists as a common image format (.jpg or .png only). If
+// so, returns the discovered extension (e.g. "jpg") and boolean true.
+// Otherwise returns an empty string and boolean false.
+func pathAsImage(extensionlessPath string) (string, bool) {
+ // extensions must be lowercased
+ formats := []string{"jpg", "png"}
+
+ for _, format := range formats {
+ _, err := os.Stat(extensionlessPath + "." + format)
+ if err != nil {
+ continue
+ }
+
+ return format, true
+ }
+
+ return "", false
+}
+
func renderView(layout, view, target string, locals map[string]interface{}) error {
log.Debugf("Rendering: %v", target)
diff --git a/content/articles/acid.md b/content/articles/acid.md
index 06151484c..eacbe5744 100644
--- a/content/articles/acid.md
+++ b/content/articles/acid.md
@@ -6,8 +6,6 @@ hook: On ensuring system integrity, operability, and
correctness through a solid foundational database, and
how ACID transactions and strong constraints work in your
favor. Why to prefer Postgres over MongoDB.
-hook_image: true
-twitter_image: true
---
In 1983, Andreas Reuter and Theo Härder coined the acronym
diff --git a/content/articles/api-paradigms.md b/content/articles/api-paradigms.md
index 4b8e7ecb4..7be31f033 100644
--- a/content/articles/api-paradigms.md
+++ b/content/articles/api-paradigms.md
@@ -5,8 +5,6 @@ location: San Francisco
hook: Musings on the next API technology, and whether REST-ish
JSON over HTTP is just "good enough" to never be displaced
in a significant way.
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=14003134
---
diff --git a/content/articles/breaktime.md b/content/articles/breaktime.md
index 9603e8ef1..f61c3d97c 100644
--- a/content/articles/breaktime.md
+++ b/content/articles/breaktime.md
@@ -4,7 +4,6 @@ published_at: 2014-02-02T18:15:28Z
location: San Francisco
hook: In search of an alternative to BreakTime. The
discovery of a very classical solution.
-hook_image: true
---
A few years ago I took the plunge and started using
diff --git a/content/articles/heroku-values.md b/content/articles/heroku-values.md
index ff595480f..7dc5623b5 100644
--- a/content/articles/heroku-values.md
+++ b/content/articles/heroku-values.md
@@ -4,8 +4,6 @@ image: "/assets/heroku-values/heroku-values.jpg"
location: San Francisco
published_at: 2015-11-05T06:20:16Z
title: My Heroku Values
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=14286143
---
diff --git a/content/articles/idempotency-keys.md b/content/articles/idempotency-keys.md
index 8ea9fb73a..63a36e269 100644
--- a/content/articles/idempotency-keys.md
+++ b/content/articles/idempotency-keys.md
@@ -6,8 +6,6 @@ hook: Building resilient services by identifying foreign
state mutations and grouping local changes into
restartable atomic phases so that every request can be
driven to completion.
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=15569478
---
diff --git a/content/articles/interfaces.md b/content/articles/interfaces.md
index f1d90a256..9add4cc9d 100644
--- a/content/articles/interfaces.md
+++ b/content/articles/interfaces.md
@@ -5,8 +5,6 @@ location: San Francisco
hook: How we overvalue the wrong technology and novel
aspects of interface design at the expense of substantial
gains to our productivity.
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=13733777
---
diff --git a/content/articles/minimalism.md b/content/articles/minimalism.md
index ebca3937b..a0dd573ba 100644
--- a/content/articles/minimalism.md
+++ b/content/articles/minimalism.md
@@ -5,8 +5,6 @@ location: San Francisco
hook: Practicing minimalism with the lofty goal of total
ephemeralization to build coherent, stable, and operable
stacks.
-hook_image: true
-twitter_image: true
attributions: Photographs by Ben Harrington (SR-71), Robyn Jay (embers of a burning fire), and Md. Al Amin (boat and sky). Licensed under Creative Commons BY-NC-ND 2.0, BY-SA 2.0, and CC BY 2.0 respectively.
---
diff --git a/content/articles/newsletters.md b/content/articles/newsletters.md
index 0c488d3f1..61d26054f 100644
--- a/content/articles/newsletters.md
+++ b/content/articles/newsletters.md
@@ -3,8 +3,6 @@ title: "Pseudo-HTML and Pidgin CSS: Building an Email Newsletter"
published_at: 2017-08-02T14:52:31Z
hook: Building a toolchain for sending a newsletter, and
the dismal state of HTML and CSS in email.
-hook_image: true
-twitter_image: true
---
After a recent trip to Portland, I decided to try writing a
diff --git a/content/articles/page.md b/content/articles/page.md
index ec6a439c8..d9ec134c9 100644
--- a/content/articles/page.md
+++ b/content/articles/page.md
@@ -3,8 +3,6 @@ hook: How the page almost transitioned successfully to the
digital world, but is in decline in new media. The
lessons that we can learn from this age-old design
element, and why we should hope for its re-emergence.
-hook_image: true
-twitter_image: true
image: "/assets/page/page.jpg"
location: San Francisco
published_at: 2014-01-26T18:56:46Z
diff --git a/content/articles/postgres-atomicity.md b/content/articles/postgres-atomicity.md
index a7cfe356a..0a5fadd8d 100644
--- a/content/articles/postgres-atomicity.md
+++ b/content/articles/postgres-atomicity.md
@@ -5,8 +5,6 @@ location: San Francisco
hook: A dive into the mechanics that allow Postgres to
provide strong atomic guarantees despite the chaotic
entropy of production.
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=15027870
---
diff --git a/content/articles/postgres-reads.md b/content/articles/postgres-reads.md
index 6df94eb2b..44bea2175 100644
--- a/content/articles/postgres-reads.md
+++ b/content/articles/postgres-reads.md
@@ -6,8 +6,6 @@ published_at: 2017-11-17T22:02:56Z
hook: Scaling out operation with read replicas and avoiding
the downside of stale reads by observing replication
progress.
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=15726376
---
diff --git a/content/articles/redis-streams.md b/content/articles/redis-streams.md
index c85759f6b..8a9cdf200 100644
--- a/content/articles/redis-streams.md
+++ b/content/articles/redis-streams.md
@@ -5,8 +5,6 @@ location: San Francisco
hook: Building a log-based architecture that's fast,
efficient, and resilient on the new stream data structure
in Redis.
-hook_image: true
-twitter_image: true
hn_link: https://news.ycombinator.com/item?id=15653544
---
diff --git a/content/articles/stripe-running.md b/content/articles/stripe-running.md
index 3cc43491e..d2502c981 100644
--- a/content/articles/stripe-running.md
+++ b/content/articles/stripe-running.md
@@ -3,7 +3,6 @@ hook: Crunching running data with prepared statements in Postgres.
location: San Francisco
published_at: 2015-10-24T20:55:32Z
title: Running at Stripe
-hook_image: true
---
One pleasant surprise of Stripe's internal culture was the existence of a
diff --git a/content/articles/webhooks.md b/content/articles/webhooks.md
index e98bbeceb..75054ea6a 100644
--- a/content/articles/webhooks.md
+++ b/content/articles/webhooks.md
@@ -6,8 +6,6 @@ hook: When it comes to streaming APIs, there's now a lot of
great options like SSE, GraphQL subscriptions, and GRPC
streams. Let's examine whether webhooks are still a good
choice in 2017.
-hook_image: true
-twitter_image: true
attributions: Thanks to Spencer
Dixon for review.
diff --git a/content/articles/x100s-hack.md b/content/articles/x100s-hack.md
index f45f30535..a80f3c156 100644
--- a/content/articles/x100s-hack.md
+++ b/content/articles/x100s-hack.md
@@ -4,8 +4,6 @@ hook: If you find that the price tag for a Fuji-official adapter ring for the X1
location: San Francisco
published_at: 2014-08-03T16:50:19Z
title: A Cheap X100S Filter Ring Hack
-hook_image: true
-twitter_image: true
---
The [official Fujifilm X100/X100S 49 mm adapter ring](http://www.amazon.com/Fujifilm-AR-X100-Adapter-Ring-49mm/dp/B004MME69S) which allows you to mount extra filters onto your lens will run you about $40, which is a little steep considering that its entire role in life is to act as an expensive spacer.
diff --git a/content/drafts/microservices-and-the-monolith.md b/content/drafts/microservices-and-the-monolith.md
index c92851169..f7027ff5c 100644
--- a/content/drafts/microservices-and-the-monolith.md
+++ b/content/drafts/microservices-and-the-monolith.md
@@ -3,8 +3,6 @@ title: Microservices and the Monolith
published_at: 2017-01-05T16:41:25Z
hook: Microservices may be out of vogue, but we should be
wary of overcompensation.
-hook_image: true
-twitter_image: true
---
About three years ago, the idea of a service-oriented
diff --git a/content/drafts/ruby-scale.md b/content/drafts/ruby-scale.md
index e49f5e12b..1044c42c2 100644
--- a/content/drafts/ruby-scale.md
+++ b/content/drafts/ruby-scale.md
@@ -4,8 +4,6 @@ published_at: 2017-04-18T14:23:28Z
location: San Francisco
hook: The challenges of scaling and operating a big Ruby
codebase (that are not related to performance).
-hook_image: true
-twitter_image: true
---
Ruby is a beautiful language. Speaking from experience,
diff --git a/content/fragments/airpods.md b/content/fragments/airpods.md
index 5041de27a..abb1d3b10 100644
--- a/content/fragments/airpods.md
+++ b/content/fragments/airpods.md
@@ -2,7 +2,6 @@
title: AirPods
published_at: 2017-03-29T14:44:33Z
image: /assets/fragments/airpods/vista.jpg
-twitter_image: true
hook: I'm happy to be cheering from the bleachers as Apple
makes their first home run in years.
---
diff --git a/content/fragments/ipad-mini.md b/content/fragments/ipad-mini.md
index 0cb680a16..34379944a 100644
--- a/content/fragments/ipad-mini.md
+++ b/content/fragments/ipad-mini.md
@@ -2,7 +2,6 @@
title: The iPad Mini
published_at: 2016-06-12T22:26:17Z
image: /assets/fragments/ipad-mini/vista.jpg
-twitter_image: true
hook: An ode to one of my favorite Apple devices.
---
diff --git a/content/fragments/ivy.md b/content/fragments/ivy.md
index e01d72374..8e71d1b3c 100644
--- a/content/fragments/ivy.md
+++ b/content/fragments/ivy.md
@@ -1,7 +1,6 @@
---
title: Ivy
published_at: 2016-08-24T03:12:31Z
-twitter_image: true
image: /assets/fragments/ivy/vista.jpg
hook: Stripe's new home in SOMA.
---
diff --git a/content/fragments/monkeybrains.md b/content/fragments/monkeybrains.md
index 00ce9b1af..8629db7e0 100644
--- a/content/fragments/monkeybrains.md
+++ b/content/fragments/monkeybrains.md
@@ -2,7 +2,6 @@
title: MonkeyBrains
published_at: 2016-01-23T01:15:58Z
image: /assets/fragments/monkeybrains/vista.jpg
-twitter_image: true
hook: A very brief review of the local San Francisco ISP.
---
diff --git a/content/fragments/sprawl-blues.md b/content/fragments/sprawl-blues.md
index fdfc04586..3dea6d7e1 100644
--- a/content/fragments/sprawl-blues.md
+++ b/content/fragments/sprawl-blues.md
@@ -2,7 +2,6 @@
title: The Sprawl Blues
published_at: 2016-01-03T22:18:36Z
image: /assets/fragments/sprawl-blues/vista.jpg
-twitter_image: true
hook: On sprawl and commute times in North America.
---
diff --git a/content/fragments/wgt-2015.md b/content/fragments/wgt-2015.md
index d5f91107f..1a676d74a 100644
--- a/content/fragments/wgt-2015.md
+++ b/content/fragments/wgt-2015.md
@@ -2,7 +2,6 @@
title: WGT 2015 Abstract
published_at: 2015-05-29T13:34:59Z
image: /assets/fragments/wgt-2015/vista.jpg
-twitter_image: true
hook: A whirlwind tour of Wave-Gotik-Treffen 2015.
---
diff --git a/content/fragments/your-name.md b/content/fragments/your-name.md
index 457fddb2b..d1a3dde20 100644
--- a/content/fragments/your-name.md
+++ b/content/fragments/your-name.md
@@ -2,7 +2,6 @@
title: Your Name
published_at: 2017-04-11T01:26:59Z
image: /assets/fragments/your-name/vista.jpg
-twitter_image: true
hook: A short review of Makoto Shinka's latest animated
film.
---
diff --git a/views/articles/index.ace b/views/articles/index.ace
index 8ba057899..72b465c8a 100644
--- a/views/articles/index.ace
+++ b/views/articles/index.ace
@@ -25,9 +25,9 @@
ul
{{range .Articles}}
li
- {{if .HookImage}}
+ {{if .HookImageURL}}
a href="/{{.Slug}}"
- img src="/assets/{{.Slug}}/hook.jpg" data-rjs="2"
+ img src="{{.HookImageURL}}" data-rjs="2"
{{end}}
.title
a href="/{{.Slug}}"