Add RSS subscribe links with icon across blog pages, footer, and head

- Add <.rss_icon> inline SVG component in core_components.ex
- Inject RSS <link> tags into <head> on blog pages for auto-discovery
- Show RSS icon next to blog title on index and tag pages
- Show RSS icon on post pages next to back-link
- Add Subscribe section in footer with links to both feeds
- Wire feed URL through blog controller (index, show, tag actions)

174 tests pass, credo clean.
This commit is contained in:
2026-07-08 17:00:11 +01:00
parent 9238ecb7f3
commit 855b6cb590
7 changed files with 111 additions and 7 deletions
@@ -9,9 +9,11 @@ defmodule FirehoseWeb.BlogController do
result = blog.paginate(page)
meta = Blogex.SEO.meta_tags_for_blog(blog, FirehoseWeb.Endpoint.url())
rss_url = rss_feed_url(blog)
conn
|> FirehoseWeb.Layouts.put_content_for(:meta_tags, meta)
|> FirehoseWeb.Layouts.put_content_for(:feed_links, %{rss_url: rss_url, title: blog.title()})
|> render(:index,
page_title: blog.title(),
blog_title: blog.title(),
@@ -19,7 +21,8 @@ defmodule FirehoseWeb.BlogController do
posts: result.entries,
base_path: blog.base_path(),
page: result.page,
total_pages: result.total_pages
total_pages: result.total_pages,
rss_feed_url: rss_url
)
end
@@ -27,31 +30,40 @@ defmodule FirehoseWeb.BlogController do
blog = conn.assigns.blog
post = blog.get_post!(slug)
visibility = Blogex.Post.visibility(post)
rss_url = rss_feed_url(blog)
meta = Blogex.SEO.meta_tags(post, FirehoseWeb.Endpoint.url(), blog)
conn
|> FirehoseWeb.Layouts.put_content_for(:meta_tags, meta)
|> FirehoseWeb.Layouts.put_content_for(:feed_links, %{rss_url: rss_url, title: blog.title()})
|> render(:show,
page_title: post.title,
post: post,
meta: meta,
base_path: blog.base_path(),
visibility: visibility,
authenticated: !!(conn.assigns[:current_scope] && conn.assigns.current_scope.user)
authenticated: !!(conn.assigns[:current_scope] && conn.assigns.current_scope.user),
rss_feed_url: rss_url
)
end
def tag(conn, %{"tag" => tag}) do
blog = conn.assigns.blog
posts = blog.posts_by_tag(tag)
rss_url = rss_feed_url(blog)
render(conn, :tag,
rss_link = %{rss_url: rss_url, title: blog.title()}
conn
|> FirehoseWeb.Layouts.put_content_for(:feed_links, rss_link)
|> render(:tag,
page_title: "#{blog.title()}#{tag}",
blog_title: blog.title(),
tag: tag,
posts: posts,
base_path: blog.base_path()
base_path: blog.base_path(),
rss_feed_url: rss_url
)
end
@@ -77,4 +89,9 @@ defmodule FirehoseWeb.BlogController do
_ -> 1
end
end
defp rss_feed_url(blog) do
base_id = blog.base_path() |> String.trim_leading("/blog/")
FirehoseWeb.Endpoint.url() <> "/api/blog/#{base_id}/feed.xml"
end
end
@@ -1,6 +1,17 @@
<div class="space-y-8">
<header>
<h1 class="text-3xl font-bold font-display">{@blog_title}</h1>
<div class="flex items-center gap-3">
<h1 class="text-3xl font-bold font-display">{@blog_title}</h1>
<a
href={@rss_feed_url}
class="link link-hover text-orange-500 hover:text-orange-600 transition-colors"
title="Subscribe to {@blog_title} RSS feed"
target="_blank"
rel="noopener noreferrer"
>
<.rss_icon class="size-5" />
</a>
</div>
<p :if={@blog_description} class="mt-2 text-base-content/70">{@blog_description}</p>
</header>
@@ -1,5 +1,16 @@
<div class="space-y-8">
<a href={@base_path} class="text-sm text-primary hover:underline">&larr; Back to posts</a>
<div class="flex items-center justify-between">
<a href={@base_path} class="text-sm text-primary hover:underline">&larr; Back to posts</a>
<a
href={@rss_feed_url}
class="link link-hover text-orange-500 hover:text-orange-600 transition-colors"
title="Subscribe to RSS feed"
target="_blank"
rel="noopener noreferrer"
>
<.rss_icon class="size-5" />
</a>
</div>
<%= if @authenticated and @visibility == :draft do %>
<div
@@ -1,6 +1,17 @@
<div class="space-y-8">
<header>
<h1 class="text-3xl font-bold font-display">{@blog_title}</h1>
<div class="flex items-center gap-3">
<h1 class="text-3xl font-bold font-display">{@blog_title}</h1>
<a
href={@rss_feed_url}
class="link link-hover text-orange-500 hover:text-orange-600 transition-colors"
title="Subscribe to {@blog_title} RSS feed"
target="_blank"
rel="noopener noreferrer"
>
<.rss_icon class="size-5" />
</a>
</div>
<p class="mt-2 text-base-content/70">Posts tagged "{@tag}"</p>
</header>