diff --git a/assets/css/app.scss b/assets/css/app.scss index 7754710..bb6ce2d 100644 --- a/assets/css/app.scss +++ b/assets/css/app.scss @@ -47,12 +47,21 @@ body { height: 100%; } a { - color: $secondary; + color: $gray-100; + border-bottom: $secondary 2px solid; + text-decoration: none; + &.navbar-brand { + border-bottom: none; + } &:visited { color: $info; + .post-title & { + color: $gray-100; + } } &:hover { color: $primary; + text-decoration: none; } } .border-gray-900 { @@ -94,6 +103,7 @@ a { /* social icons */ #social-icons .link-light { + border-bottom: none; color: $gray-100; &:hover { color: $primary; @@ -128,9 +138,10 @@ a { .post-title a { color: $gray-100; text-decoration: none; + border-bottom: none; &:hover { color: $primary; - text-decoration: underline; + border-bottom: $secondary 3px solid; } } .post-lede, diff --git a/lib/home73k/blog.ex b/lib/home73k/blog.ex index 7f002f6..db9ba4b 100644 --- a/lib/home73k/blog.ex +++ b/lib/home73k/blog.ex @@ -3,21 +3,29 @@ defmodule Home73k.Blog do Application.ensure_all_started(:earmark) - posts_paths = "#{Home73k.app_blog_content()}/**/*.md" |> Path.wildcard() + post_paths = "#{Home73k.app_blog_content()}/**/*.md" |> Path.wildcard() + post_paths_hash = :erlang.md5(post_paths) posts = - for post_path <- posts_paths do + for post_path <- post_paths do @external_resource Path.relative_to_cwd(post_path) Post.parse!(post_path) end + def __mix_recompile__?() do + Path.wildcard("#{Home73k.app_blog_content()}/**/*.md") |> :erlang.md5() != unquote(post_paths_hash) + end + @posts Enum.sort_by(posts, & &1.date, {:desc, Date}) + @post_count length(@posts) @tags posts |> Stream.flat_map(& &1.tags) |> Stream.uniq() |> Enum.sort() def list_posts, do: @posts def list_tags, do: @tags + def post_count, do: @post_count + defmodule NotFoundError do defexception [:message, plug_status: 404] end @@ -29,10 +37,10 @@ defmodule Home73k.Blog do end end - # def get_posts_by_tag!(tag) do - # case Enum.filter(list_posts(), &(tag in &1.tags)) do - # [] -> raise NotFoundError, "posts with tag=#{tag} not found" - # posts -> posts - # end - # end + def get_posts_by_tag!(tag) do + case Enum.filter(list_posts(), &(tag in &1.tags)) do + [] -> raise NotFoundError, "posts with tag=#{tag} not found" + posts -> posts + end + end end diff --git a/lib/home73k_web.ex b/lib/home73k_web.ex index 6da50d5..29f5403 100644 --- a/lib/home73k_web.ex +++ b/lib/home73k_web.ex @@ -93,9 +93,6 @@ defmodule Home73kWeb do # Import SVG Icon helper import Home73kWeb.IconHelpers - # Import Date formatter helper - import Home73kWeb.DateHelpers - import Home73kWeb.ErrorHelpers import Home73kWeb.Gettext alias Home73kWeb.Router.Helpers, as: Routes diff --git a/lib/home73k_web/live/blog_live.ex b/lib/home73k_web/live/blog_live.ex index 6100d73..ac160be 100644 --- a/lib/home73k_web/live/blog_live.ex +++ b/lib/home73k_web/live/blog_live.ex @@ -3,49 +3,96 @@ defmodule Home73kWeb.BlogLive do alias Home73k.Blog + @page_size 7 + @impl true def mount(_params, _session, socket) do - socket - |> live_okreply() + {:ok, socket} end @impl true - def handle_params(_params, _url, socket) do - socket - |> assign(:page_title, "Blog") - |> assign(:posts, Blog.list_posts()) + def handle_params(params, _url, socket) do + socket.assigns.live_action + |> init_per_live_action(socket, params) |> live_noreply() end - # @impl true - # def handle_event("suggest", %{"q" => query}, socket) do - # {:noreply, assign(socket, results: search(query), query: query)} - # end + defp page_param_as_int(page) do + try do + String.to_integer(page) + rescue + _ -> nil + end + end - # @impl true - # def handle_event("search", %{"q" => query}, socket) do - # case search(query) do - # %{^query => vsn} -> - # {:noreply, redirect(socket, external: "https://hexdocs.pm/#{query}/#{vsn}")} + defp raise_not_found(msg), do: raise Home73k.Blog.NotFoundError, msg - # _ -> - # {:noreply, - # socket - # |> put_flash(:error, "No dependencies found matching \"#{query}\"") - # |> assign(results: %{}, query: query)} - # end - # end + defp init_per_live_action(:index, socket, _params) do + socket + |> assign(:page_title, "Blog") + |> assign(:posts, get_posts_for_page!(1)) + |> assign(:page_count, get_page_count()) + |> assign_prev_next(1) + end - # defp search(query) do - # if not Home73kWeb.Endpoint.config(:code_reloader) do - # raise "action disabled when not in development" - # end + defp init_per_live_action(:page, socket, %{"page" => page}) do + page_int = page_param_as_int(page) + page_count = get_page_count() - # for {app, desc, vsn} <- Application.started_applications(), - # app = to_string(app), - # String.starts_with?(app, query) and not List.starts_with?(desc, ~c"ERTS"), - # into: %{}, - # do: {app, vsn} - # end + cond do + is_nil(page_int) || page_int <= 1 -> + push_patch(socket, to: Routes.blog_path(socket, :index)) + page_int > page_count -> + raise_not_found("there are only #{page_count} pages of posts") + + true -> + posts = get_posts_for_page!(page_int) + + socket + |> assign(:page_title, "Blog \\ Page #{page}") + |> assign(:posts, posts) + |> assign(:page_count, page_count) + |> assign_prev_next(page_int) + end + end + + defp init_per_live_action(:show, socket, %{"id" => id}) do + post = Blog.get_post_by_id!(id) + socket + |> assign(:page_title, "Blog \\ post.title") + |> assign(:posts, [post]) + |> assign(:page_count, nil) + |> assign_prev_next(0) + end + + defp init_per_live_action(:tag, socket, %{"tag" => tag}) do + socket + |> assign(:page_title, "Blog \\ ##{tag}") + |> assign(:posts, Blog.get_posts_by_tag!(tag)) + |> assign(:page_count, get_page_count()) + |> assign_prev_next(1) + end + + + defp get_posts_for_page!(1), do: Blog.list_posts() |> Enum.take(@page_size) + + defp get_posts_for_page!(page_int) do + Blog.list_posts() + |> Stream.chunk_every(@page_size) + |> Enum.at(page_int - 1) + end + + defp get_page_count, do: Integer.floor_div(Blog.post_count(), @page_size) + rem(Blog.post_count(), @page_size) + + defp assign_prev_next(socket, page_int) do + socket + |> assign(:page_prev, page_int < socket.assigns.page_count && page_int + 1 || nil) + |> assign(:page_next, page_int > 1 && page_int - 1 || nil) + end + + + def format_date(date) do + Calendar.strftime(date, "%B %-d, %Y") + end end diff --git a/lib/home73k_web/live/blog_live.html.leex b/lib/home73k_web/live/blog_live.html.leex index 5dd8a55..f41c5af 100644 --- a/lib/home73k_web/live/blog_live.html.leex +++ b/lib/home73k_web/live/blog_live.html.leex @@ -2,38 +2,74 @@