divide the blog into two topics
Bobby Grayson 3 weeks ago 2 files (+87, -7)
ADDED
lib/blog/content.ex
ADDED
lib/blog/content.ex
@@ -0,0 +1,49 @@+defmodule Blog.Content do+ @moduledoc """+ Handles parsing and categorizing posts from markdown files.+ """++ @tech_tags ~w(programming tech software coding elixir javascript phoenix blog)+ @posts_dir "priv/static/posts/"++ def list_posts do+ File.ls!(@posts_dir)+ |> Enum.map(&parse_post/1)+ end++ defp parse_post(filename) do+ content = File.read!(@posts_dir <> filename)+ %{+ title: parse_title(content),+ tags: parse_tags(content),+ content: content+ }+ end++ defp parse_title(content) do+ [_, title] = Regex.run(~r/title: (.+)/, content)+ title+ end++ defp parse_tags(content) do+ [_, tags] = Regex.run(~r/tags: (.+)/, content)+ String.split(tags, ",") |> Enum.map(&String.trim/1)+ end++ def categorize_posts(posts) do+ Enum.reduce(posts, %{tech: [], non_tech: []}, fn post, acc ->+ has_tech_tag = post.tags+ |> Enum.map(& &1.name)+ |> Enum.map(&String.downcase/1)+ |> Enum.any?(fn tag ->+ Enum.any?(@tech_tags, &(String.contains?(tag, &1)))+ end)++ if has_tech_tag do+ Map.update!(acc, :tech, fn posts -> [post | posts] end)+ else+ Map.update!(acc, :non_tech, fn posts -> [post | posts] end)+ end+ end)+ end+end
MODIFIED
lib/blog_web/live/post_live/index.ex
MODIFIED
lib/blog_web/live/post_live/index.ex
@@ -1,6 +1,7 @@defmodule BlogWeb.PostLive.Index douse BlogWeb, :live_viewalias BlogWeb.Presence+ alias Blog.Content@presence_topic "blog_presence"@@ -17,9 +18,14 @@ Phoenix.PubSub.subscribe(Blog.PubSub, @presence_topic)endposts = Blog.Content.Post.all()+ %{tech: tech_posts, non_tech: non_tech_posts} = Content.categorize_posts(posts)total_readers = Presence.list(@presence_topic) |> map_size()- {:ok, assign(socket, posts: posts, total_readers: total_readers)}+ {:ok, assign(socket,+ tech_posts: tech_posts,+ non_tech_posts: non_tech_posts,+ total_readers: total_readers+ )}enddef handle_info(%{event: "presence_diff"}, socket) do@@ -27,7 +33,6 @@ total_readers = Presence.list(@presence_topic) |> map_size(){:noreply, assign(socket, total_readers: total_readers)}end- # Add this to your index template:def render(assigns) do~H"""<div class="px-8 py-12">@@ -35,11 +40,37 @@ <div class="max-w-7xl mx-auto"><div class="mb-4 text-sm text-gray-500"><%= @total_readers %> <%= if @total_readers == 1, do: "person", else: "people" %> browsing the blog</div>- <div :for={post <- @posts} class="mb-8">- <.link navigate={~p"/post/#{post.slug}"}>- <h2 class="text-2xl font-bold"><%= post.title %></h2>- <h3 class="text-small font-bold"><%= post.tags |> Enum.map(& &1.name) |> Enum.join(", ") %></h3>- </.link>++ <div class="grid grid-cols-1 md:grid-cols-2 gap-8">+ <%!-- Tech Posts Column --%>+ <div>+ <h2 class="text-2xl font-bold mb-6 pb-2 border-b">Tech & Programming</h2>+ <div class="space-y-6">+ <div :for={post <- @tech_posts} class="mb-8">+ <.link navigate={~p"/post/#{post.slug}"}>+ <h3 class="text-xl font-bold hover:text-blue-600 transition-colors"><%= post.title %></h3>+ <p class="text-sm text-gray-600 mt-1">+ <%= post.tags |> Enum.map(& &1.name) |> Enum.join(", ") %>+ </p>+ </.link>+ </div>+ </div>+ </div>++ <%!-- Non-Tech Posts Column --%>+ <div>+ <h2 class="text-2xl font-bold mb-6 pb-2 border-b">Life & Everything Else</h2>+ <div class="space-y-6">+ <div :for={post <- @non_tech_posts} class="mb-8">+ <.link navigate={~p"/post/#{post.slug}"}>+ <h3 class="text-xl font-bold hover:text-blue-600 transition-colors"><%= post.title %></h3>+ <p class="text-sm text-gray-600 mt-1">+ <%= post.tags |> Enum.map(& &1.name) |> Enum.join(", ") %>+ </p>+ </.link>+ </div>+ </div>+ </div></div></div></div>