config: take the tab's favicon from the environment
The page gets an icon when PRO_TACTS_FAVICON names an href to show,
and none when it is unset, which is how the deployment goes;
rake dev points it at an ink-blue dot in public/favicon-dev.svg,
so the layout never has to ask whether this run is dev.
Assisted-by: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
diff --git a/Rakefile b/Rakefile
index f757efe..328c104 100644
--- a/Rakefile
+++ b/Rakefile
@@ -29,6 +29,7 @@ task :dev do
# PRO_TACTS_EXCHANGE_LOG (e.g. stderr) wins over both.
ENV["PRO_TACTS_EXCHANGE_LOG"] ||= "log/dev.log"
ENV["PRO_TACTS_INSTANCE_NAME"] ||= "pro-tacts (dev)"
+ ENV["PRO_TACTS_FAVICON"] ||= "/favicon-dev.svg"
File.truncate("log/dev.log", 0) if File.exist?("log/dev.log")
Dir.mktmpdir("pro-tacts-dev") do |dir|
diff --git a/lib/pro_tacts/admin/layout.rb b/lib/pro_tacts/admin/layout.rb
index 5c1430a..33e334d 100644
--- a/lib/pro_tacts/admin/layout.rb
+++ b/lib/pro_tacts/admin/layout.rb
@@ -52,6 +52,8 @@ module ProTacts
# The instance's name, so a tab says which server it is
# (`rake dev` names its own).
title { "#{ProTacts.config.instance_name} — #{@title}" }
+ favicon = ProTacts.config.favicon
+ link(rel: "icon", href: favicon) if favicon
# No webfont (docs/DESIGN.md), so there is no font link
# among these. What was here before was a remote Google
# Fonts stylesheet, and the self-hosted woff2s meant to
diff --git a/lib/pro_tacts/config.rb b/lib/pro_tacts/config.rb
index 3ff9e03..b58b3cd 100644
--- a/lib/pro_tacts/config.rb
+++ b/lib/pro_tacts/config.rb
@@ -71,6 +71,14 @@ module ProTacts
@env.fetch("PRO_TACTS_INSTANCE_NAME", "pro-tacts")
end
+ # The tab's icon, PRO_TACTS_FAVICON, as an href; nil leaves the page
+ # without one, which is the deployment's "no brand mark"
+ # (docs/DESIGN.md).
+ #: () -> String?
+ def favicon
+ @env.fetch("PRO_TACTS_FAVICON", nil)
+ end
+
# The running image's version, baked in as a build arg (see
# Dockerfile and the release job in ci.yml): the image tag, which is
# the GitHub release's name too — `YYYYMMDD-HHmm-<short sha>`. One
diff --git a/public/favicon-dev.svg b/public/favicon-dev.svg
new file mode 100644
index 0000000..d6f99b2
--- /dev/null
+++ b/public/favicon-dev.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><circle cx="8" cy="8" r="7" fill="#2b4a78"/></svg>
diff --git a/test/pro_tacts/admin/test_footer.rb b/test/pro_tacts/admin/test_footer.rb
index 6cd0e09..b04b4ef 100644
--- a/test/pro_tacts/admin/test_footer.rb
+++ b/test/pro_tacts/admin/test_footer.rb
@@ -83,6 +83,18 @@ class AdminFooterTest < Minitest::Test
refute_includes last_response.body, "data-server"
end
+ def test_the_tab_carries_the_configured_favicon
+ with_env("PRO_TACTS_FAVICON" => "/favicon-dev.svg")
+
+ assert_includes last_response.body, %(<link rel="icon" href="/favicon-dev.svg">)
+ end
+
+ def test_no_favicon_leaves_the_tab_bare
+ with_env({})
+
+ refute_includes last_response.body, %(rel="icon")
+ end
+
def test_the_title_names_the_instance
with_env({})
diff --git a/test/pro_tacts/test_config.rb b/test/pro_tacts/test_config.rb
index d2d0102..3067529 100644
--- a/test/pro_tacts/test_config.rb
+++ b/test/pro_tacts/test_config.rb
@@ -65,4 +65,12 @@ class ConfigTest < Minitest::Test
def test_instance_name_is_overridable
assert_equal "pro-tacts (dev)", ProTacts::Config.new("PRO_TACTS_INSTANCE_NAME" => "pro-tacts (dev)").instance_name
end
+
+ def test_favicon_is_nil_when_unset
+ assert_nil ProTacts::Config.new({}).favicon
+ end
+
+ def test_favicon_is_passed_through
+ assert_equal "/favicon-dev.svg", ProTacts::Config.new("PRO_TACTS_FAVICON" => "/favicon-dev.svg").favicon
+ end
end