Browse Source

Start displaying page titles on each HTML page

main
Jeremy Boles 2 weeks ago
parent
commit
d0f34be4ac
Signed by: jb
GPG Key ID: 7DE0508F61CB57DF
  1. 55
      lib/ann/plug.ex
  2. 20
      lib/ann/templates.ex
  3. 18
      lib/ann/templates/entry.html.eex
  4. 2
      lib/ann/templates/journal.html.eex
  5. 2
      lib/ann/templates/layout.html.eex
  6. 14
      lib/ann/templates/topic.html.eex
  7. 2
      lib/ann/templates/wiki.html.eex
  8. 8
      lib/storala/journal/entry.ex
  9. 6
      lib/storala/wiki/topic.ex
  10. 1
      mix.exs
  11. 2
      mix.lock

55
lib/ann/plug.ex

@ -6,12 +6,14 @@ defmodule Ann.Plug do
plug :dispatch
get "/" do
send_template(conn, Ann.Templates.index())
title = "Jeremy Boles"
send_template(conn, Ann.Templates.index(%{}), %{title: title})
end
get "/journal" do
entries = Storala.Journal.all() |> Enum.group_by(&day/1) |> Enum.reverse()
send_template(conn, Ann.Templates.journal(entries))
days = Storala.Journal.all() |> Enum.group_by(&day/1) |> Enum.reverse()
title = "Journal · Jeremy Boles"
send_template(conn, Ann.Templates.journal(%{days: days}), %{title: title})
end
get "/journal/:slug" do
@ -20,8 +22,9 @@ defmodule Ann.Plug do
end
get "/wiki" do
title = "Wiki · Jeremy Boles"
topics = Storala.Wiki.all()
send_template(conn, Ann.Templates.wiki(topics))
send_template(conn, Ann.Templates.wiki(%{topics: topics}), %{title: title})
end
get "/:slug" do
@ -44,24 +47,52 @@ defmodule Ann.Plug do
end
defp not_found(conn) do
resp = Ann.Templates.not_found() |> Ann.Templates.layout()
title = "Not Found · Jeremy Boles"
resp = Ann.Templates.not_found() |> Ann.Templates.layout(%{title: title})
send_html(conn, 404, resp)
end
defp send_entry(conn, nil), do: not_found(conn)
defp send_entry(conn, entry), do: send_template(conn, Ann.Templates.entry(entry))
defp send_entry(conn, nil) do
not_found(conn)
end
defp send_entry(conn, %{content_text: text} = entry) do
truncated = truncate(text)
title = "#{truncated}#{if text != truncated, do: "", else: ""}” - Journal · Jeremy Boles"
send_template(conn, Ann.Templates.entry(%{entry: entry}), %{title: title})
end
defp send_html(conn, status, resp) do
conn |> put_resp_content_type("text/html") |> send_resp(status, resp)
end
defp send_template(conn, resp), do: send_template(conn, 200, resp)
defp send_template(conn, status, resp), do: send_html(conn, status, Ann.Templates.layout(resp))
defp send_template(conn, resp, layout_local) do
send_template(conn, 200, resp, layout_local)
end
defp send_topic(conn, nil), do: not_found(conn)
defp send_template(conn, status, resp, layout_local) when is_binary(resp) do
send_html(conn, status, Ann.Templates.layout(resp, layout_local))
end
defp send_topic(conn, topic) do
defp send_topic(conn, nil) do
not_found(conn)
end
defp send_topic(conn, %{title_text: title_text} = topic) do
title = "#{title_text} - Wiki · Jeremy Boles"
updates = Storala.Wiki.Topic.get(topic, "updates")
send_template(conn, Ann.Templates.topic(topic, updates))
send_template(conn, Ann.Templates.topic(%{topic: topic, updates: updates}), %{title: title})
end
defp truncate(str, length \\ 43) do
shorter = length - 1
case str do
<<result::binary-size(shorter), " ", _::binary>> -> result
<<result::binary-size(length), " ", _::binary>> -> result
<<_::binary-size(length)>> -> str
_ when length <= 1 -> ""
_ -> truncate(str, shorter)
end
end
end

20
lib/ann/templates.ex

@ -4,12 +4,16 @@ defmodule Ann.Templates do
import Ann.Helpers
@path Path.expand("./lib/ann/templates")
EEx.function_from_file(:def, :entry, Path.join(@path, "entry.html.eex"), [:entry])
EEx.function_from_file(:def, :index, Path.join(@path, "index.html.eex"))
EEx.function_from_file(:def, :journal, Path.join(@path, "journal.html.eex"), [:days])
EEx.function_from_file(:def, :layout, Path.join(@path, "layout.html.eex"), [:inner_content])
EEx.function_from_file(:def, :topic, Path.join(@path, "topic.html.eex"), [:topic, :updates])
EEx.function_from_file(:def, :wiki, Path.join(@path, "wiki.html.eex"), [:topics])
EEx.function_from_file(:def, :not_found, Path.join(@path, "404.html.eex"))
EEx.function_from_file(:def, :entry, Path.join(@path, "entry.html.eex"), [:local])
EEx.function_from_file(:def, :index, Path.join(@path, "index.html.eex"), [:_local])
EEx.function_from_file(:def, :journal, Path.join(@path, "journal.html.eex"), [:local])
EEx.function_from_file(:def, :topic, Path.join(@path, "topic.html.eex"), [:local])
EEx.function_from_file(:def, :wiki, Path.join(@path, "wiki.html.eex"), [:local])
EEx.function_from_file(:def, :not_found, Path.join(@path, "404.html.eex"), [])
EEx.function_from_file(:def, :layout, Path.join(@path, "layout.html.eex"), [
:inner_content,
:local
])
end

18
lib/ann/templates/entry.html.eex

@ -1,35 +1,35 @@
<article class="entry">
<header>
<h1>
<a href="/journal/<%= Storala.Journal.Entry.get(entry, "slug") %>/"><%= if entry.kind == "checkin" do %>Checked in at <i><%= place Storala.Journal.Entry.get(entry, "place") %></i><% else %><%= String.capitalize(entry.kind) %> posted from <i><%= city Storala.Journal.Entry.get(entry, "location") %></i><% end %></a>
<a href="/journal/<%= Storala.Journal.Entry.get(local.entry, "slug") %>/"><%= if local.entry.kind == "checkin" do %>Checked in at <i><%= place Storala.Journal.Entry.get(local.entry, "place") %></i><% else %><%= String.capitalize(local.entry.kind) %> posted from <i><%= city Storala.Journal.Entry.get(local.entry, "location") %></i><% end %></a>
<span>on</span>
<time datetime="<%= Storala.Journal.Entry.get(entry, "published_at") |> DateTime.to_iso8601() %>"><%= date Storala.Journal.Entry.get(entry, "published_at"), Storala.Journal.Entry.get(entry, "location") %></time>
<time datetime="<%= Storala.Journal.Entry.get(local.entry, "published_at") |> DateTime.to_iso8601() %>"><%= date Storala.Journal.Entry.get(local.entry, "published_at"), Storala.Journal.Entry.get(local.entry, "location") %></time>
</h1>
<%= if Enum.count(entry.tags) > 0 do %>
<p><span>Tagged with:</span> <%= entry.tags |> Enum.map(fn t -> "<i>#{t}</i>" end) |> Enum.join(" ") %></p>
<%= if Enum.count(local.entry.tags) > 0 do %>
<p><span>Tagged with:</span> <%= local.entry.tags |> Enum.map(fn t -> "<i>#{t}</i>" end) |> Enum.join(" ") %></p>
<% end %>
</header>
<%= entry.content_html %>
<%= local.entry.content_html %>
<aside>
<details>
<summary>Status at Time of Entry</summary>
<dl>
<%= if coordinates = Storala.Journal.Entry.get(entry, "coordinates") do %>
<%= if coordinates = Storala.Journal.Entry.get(local.entry, "coordinates") do %>
<dt>Coordinates</dt>
<dd><%= dms coordinates %></dd>
<% end %>
<%= if location = Storala.Journal.Entry.get(entry, "location") do %>
<%= if location = Storala.Journal.Entry.get(local.entry, "location") do %>
<dt>Location</dt>
<dd><%= city location %></dd>
<% end %>
<%= if weather = Storala.Journal.Entry.get(entry, "weather") do %>
<%= if weather = Storala.Journal.Entry.get(local.entry, "weather") do %>
<dt>Weather</dt>
<dd><%= temperature weather %> &amp; <%= conditions weather %></dd>
<% end %>
<%= if activity = Storala.Journal.Entry.get(entry, "activity") do %>
<%= if activity = Storala.Journal.Entry.get(local.entry, "activity") do %>
<dt>Steps</dt>
<dd><%= steps activity %> Steps (<%= distance activity %>)</dd>
<% end %>

2
lib/ann/templates/journal.html.eex

@ -3,7 +3,7 @@
<p>This little corner of my website is the “social” section, such as it is. It’s where I publish things that one would typically add to Twitter, Facebook, or Instagram. Instead, they live here, on my website, and I syndicate to those places. Learn more about this style of publishing on my <a href="/indieweb/">IndieWeb topic page</a>.</p>
<dl>
<%= for {day, entries} <- days do %>
<%= for {day, entries} <- local.days do %>
<dt>
<time datetime="<%= Date.to_iso8601(day) %>"><%= Calendar.strftime(day, "%A, %B %-d %Y") %></time>
</dt>

2
lib/ann/templates/layout.html.eex

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Jeremy Boles</title>
<title><%= local.title %></title>
<link href="/css/styles.css" rel="stylesheet">
<link href="/favicon.ico" rel="shortcut icon" sizes="32x32" type="image/x-icon">
<link href="/knot.png" rel="icon" sizes="16x16" type="image/png">

14
lib/ann/templates/topic.html.eex

@ -1,18 +1,18 @@
<article class="topic">
<header>
<h1><%= topic.title_html %></h1>
<%= if Enum.count(topic.tags) > 0 do %>
<p><span>Tagged with:</span> <%= topic.tags |> Enum.map(fn t -> "<i>#{t}</i>" end) |> Enum.join(" ") %></p>
<h1><%= local.topic.title_html %></h1>
<%= if Enum.count(local.topic.tags) > 0 do %>
<p><span>Tagged with:</span> <%= local.topic.tags |> Enum.map(fn t -> "<i>#{t}</i>" end) |> Enum.join(" ") %></p>
<% end %>
</header>
<%= topic.content_html %>
<%= local.topic.content_html %>
<footer>
<p>
The topic <b><%= topic.title_html %></b> was published <%= created_at(updates) %> from <%= created_from(updates) %>.
<%= if Enum.count(updates) > 1 do %>
It’s has been updated <%= count(updates) %> <%= inflect("time", updates) %>, the last time being <%= updated_at(updates) %>, from <%= updated_from(updates) %>.
The topic <b><%= local.topic.title_html %></b> was published <%= created_at(local.updates) %> from <%= created_from(local.updates) %>.
<%= if Enum.count(local.updates) > 1 do %>
It’s has been updated <%= count(local.updates) %> <%= inflect("time", local.updates) %>, the last time being <%= updated_at(local.updates) %>, from <%= updated_from(local.updates) %>.
<% else %>
It’s has not been updated since its initial publication.
<% end %>

2
lib/ann/templates/wiki.html.eex

@ -3,7 +3,7 @@
<p>Here are all of the topics that I’ve collected information about so far. I thought it would be neat to collect my own thoughts about the things I do and then store them in one place where I can link everything together. Nearly everything on my website is attached to a wiki topic in one way or another.</p>
<ol>
<%= for topic <- topics do %>
<%= for topic <- local.topics do %>
<li><a href="/<%= Storala.Wiki.Topic.get(topic, "slug") %>/"><%= topic.title_html %></a></li>
<% end %>
</ol>

8
lib/storala/journal/entry.ex

@ -1,7 +1,7 @@
defmodule Storala.Journal.Entry do
alias Storala.{Data, Markdown}
use Markdown, id: nil, kind: nil
use Markdown, content_text: nil, id: nil, kind: nil
def get(%__MODULE__{} = topic, "slug"), do: Data.cascade(topic, "slug") |> get_slug(topic)
def get(%__MODULE__{} = topic, key), do: Data.cascade(topic, key)
@ -9,6 +9,11 @@ defmodule Storala.Journal.Entry do
def new(%Markdown{} = struct), do: struct |> Map.from_struct() |> new()
def new(map), do: struct(__MODULE__, map_fields(map))
def extract_content_text(%{content_html: html} = map) do
content_text = HtmlSanitizeEx.strip_tags(html) |> String.trim()
Map.put(map, :content_text, content_text)
end
defp extract_id(filename) do
case Regex.scan(~r/^[\d]{4}\-(\w{5})\..*$/, Path.basename(filename, ".md")) do
[[_, id]] -> id
@ -30,5 +35,6 @@ defmodule Storala.Journal.Entry do
map
|> Map.put(:id, extract_id(filename))
|> Map.put(:kind, extract_kind(filename))
|> extract_content_text()
end
end

6
lib/storala/wiki/topic.ex

@ -1,7 +1,7 @@
defmodule Storala.Wiki.Topic do
alias Storala.{Data, Markdown}
use Markdown, id: nil, kind: "topic", title_html: nil
use Markdown, id: nil, kind: "topic", title_html: nil, title_text: nil
def get(%__MODULE__{} = topic, "slug"), do: Data.cascade(topic, "slug") |> get_slug(topic)
def get(%__MODULE__{} = topic, key), do: Data.cascade(topic, key)
@ -14,15 +14,15 @@ defmodule Storala.Wiki.Topic do
extract_title(map, tree)
end
defp extract_title(map, nil), do: map
defp extract_title(%{content_html: html} = map, [{"h1", [], contents}] = tree) do
content_html = String.replace(html, Floki.raw_html(tree), "") |> String.trim()
title_html = contents |> Floki.raw_html() |> String.trim()
title_text = HtmlSanitizeEx.strip_tags(title_html) |> String.trim()
map
|> Map.put(:content_html, content_html)
|> Map.put(:title_html, title_html)
|> Map.put(:title_text, title_text)
end
defp get_slug(nil, %__MODULE__{id: id}), do: id

1
mix.exs

@ -30,6 +30,7 @@ defmodule Ann.MixProject do
{:geo, "~> 3.4"},
{:geocalc, "~> 0.8.4"},
{:geohash, "~> 1.2.2"},
{:html_sanitize_ex, "~> 1.4.2"},
{:inflex, "~> 2.1.0"},
{:number, "~> 1.0.3"},
{:plug, "~> 1.13"},

2
mix.lock

@ -18,12 +18,14 @@
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"hpax": {:hex, :hpax, "0.1.1", "2396c313683ada39e98c20a75a82911592b47e5c24391363343bde74f82396ca", [:mix], [], "hexpm", "0ae7d5a0b04a8a60caf7a39fcf3ec476f35cc2cc16c05abea730d3ce6ac6c826"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.2", "c479398b6de798c03eb5d04a0a9a9159d73508f83f6590a00b8eacba3619cf4c", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "aef6c28585d06a9109ad591507e508854c5559561f950bbaea773900dd369b0e"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mochiweb": {:hex, :mochiweb, "2.22.0", "f104d6747c01a330c38613561977e565b788b9170055c5241ac9dd6e4617cba5", [:rebar3], [], "hexpm", "cbbd1fd315d283c576d1c8a13e0738f6dafb63dc840611249608697502a07655"},
"number": {:hex, :number, "1.0.3", "932c8a2d478a181c624138958ca88a78070332191b8061717270d939778c9857", [:mix], [{:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "dd397bbc096b2ca965a6a430126cc9cf7b9ef7421130def69bcf572232ca0f18"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"},

Loading…
Cancel
Save