Merge branch 'main' of dokku:firehose.apps.sustainabledelivery.com
This commit is contained in:
commit
4ead5702fb
@ -420,6 +420,30 @@ defmodule FirehoseWeb.CoreComponents do
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders an RSS feed icon (inline SVG).
|
||||
|
||||
## Examples
|
||||
|
||||
<.rss_icon class="size-5" />
|
||||
"""
|
||||
attr :class, :string, default: "size-4"
|
||||
attr :rest, :global
|
||||
|
||||
def rss_icon(assigns) do
|
||||
~H"""
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class={[@class]}
|
||||
{@rest}
|
||||
>
|
||||
<path d="M6.18 15.64a2.18 2.18 0 0 1 2.18 2.18C8.36 19 7.38 20 6.18 20C5 20 4 19 4 17.82a2.18 2.18 0 0 1 2.18-2.18M4 4.44A15.56 15.56 0 0 1 19.56 20h-2.83A12.73 12.73 0 0 0 4 7.27V4.44m0 5.66a9.9 9.9 0 0 1 9.9 9.9h-2.83A7.07 7.07 0 0 0 4 12.93v-2.83Z" />
|
||||
</svg>
|
||||
"""
|
||||
end
|
||||
|
||||
## JS Commands
|
||||
|
||||
def show(js \\ %JS{}, selector) do
|
||||
|
||||
@ -39,4 +39,30 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="border-t border-base-200 px-4 py-8 sm:px-6 lg:px-8">
|
||||
<div class="mx-auto max-w-2xl space-y-3">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-base-content/60 uppercase">Subscribe</h3>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<a
|
||||
href="/api/blog/engineering/feed.xml"
|
||||
class="inline-flex items-center gap-2 text-sm text-base-content/70 hover:text-primary transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<.rss_icon class="size-4 text-orange-500" />
|
||||
Engineering Blog
|
||||
</a>
|
||||
<a
|
||||
href="/api/blog/releases/feed.xml"
|
||||
class="inline-flex items-center gap-2 text-sm text-base-content/70 hover:text-primary transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<.rss_icon class="size-4 text-orange-500" />
|
||||
Release Notes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<.flash_group flash={@flash} />
|
||||
|
||||
@ -41,6 +41,9 @@
|
||||
<% end %>
|
||||
<meta name="twitter:card" content={meta.twitter_card} />
|
||||
<% end %>
|
||||
<%= for feed <- get_content_for(assigns, :feed_links) do %>
|
||||
<link rel="alternate" type="application/rss+xml" title={feed.title} href={feed.rss_url} />
|
||||
<% end %>
|
||||
</head>
|
||||
<body>
|
||||
{@inner_content}
|
||||
|
||||
@ -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">← Back to posts</a>
|
||||
<div class="flex items-center justify-between">
|
||||
<a href={@base_path} class="text-sm text-primary hover:underline">← 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>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ defmodule Firehose.MixProject do
|
||||
def project do
|
||||
[
|
||||
app: :firehose,
|
||||
version: "0.1.0",
|
||||
version: "0.2.0",
|
||||
elixir: "~> 1.15",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
start_permanent: Mix.env() == :prod,
|
||||
|
||||
16
app/priv/blog/release-notes/2026/07-08-v0-2-0.md
Normal file
16
app/priv/blog/release-notes/2026/07-08-v0-2-0.md
Normal file
@ -0,0 +1,16 @@
|
||||
%{
|
||||
title: "v0.2.0 — RSS Subscribe Links",
|
||||
author: "Willem van den Ende",
|
||||
tags: ~w(release),
|
||||
description: "RSS feed subscribe links with classic waveguide icons across blog pages, post pages, and site footer."
|
||||
}
|
||||
---
|
||||
|
||||
RSS feeds have always been available at `/api/blog/engineering/feed.xml` and `/api/blog/releases/feed.xml`, but they were never advertised. This release adds subscribe links throughout the site.
|
||||
|
||||
## What's new
|
||||
|
||||
- RSS `<link>` tags in `<head>` on all blog pages for browser/feed reader auto-discovery
|
||||
- Orange RSS icon next to blog title on index pages
|
||||
- RSS icon on each post page
|
||||
- Subscribe section in the footer with links to both feeds
|
||||
@ -90,9 +90,9 @@ defmodule FirehoseWeb.MicroprintsLiveTest do
|
||||
assert html =~ ~s(phx-value-path="#{file_a}")
|
||||
assert html =~ "Collapse"
|
||||
|
||||
# Highlight a line in file B via direct event (avoids brittle DOM selector)
|
||||
view
|
||||
|> render_click("highlight_line", %{"line" => "1", "path" => file_b})
|
||||
# Highlight a line in file B by dispatching the highlight_line event
|
||||
# (microprint renders multiple rect segments per line, element() can't pick one)
|
||||
render_click(view, "highlight_line", %{"line" => "1", "path" => file_b})
|
||||
|
||||
# file A should be collapsed when highlighting a different file
|
||||
html = render(view)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user