Use Tailwind dark: toggles for dark-mode icons
The previous <picture media="(prefers-color-scheme: dark)"> only fires when the OS is in dark mode. Clinch toggles dark mode with a class on <html> via dark_mode_controller and Tailwind's @custom-variant dark (&:where(.dark, .dark *)), so the picture source never swapped when users clicked the in-app theme toggle. Render both <img> tags and use Tailwind's dark:hidden / hidden dark:block so the swap follows whatever strategy Tailwind is configured for. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -70,19 +70,23 @@ module ApplicationHelper
|
||||
MONOGRAM_PALETTE[index]
|
||||
end
|
||||
|
||||
# Renders an application icon as a <picture> that swaps based on the user's
|
||||
# color-scheme preference. If only `icon` is attached, the same image is used
|
||||
# in both modes. Caller is responsible for ensuring at least app.icon is
|
||||
# attached; the monogram fallback handles the no-icon case separately.
|
||||
# Renders an application icon with optional dark-mode variant. If
|
||||
# `icon_dark` is attached, we render both <img> tags and Tailwind's class-
|
||||
# based `dark:` modifier hides the inactive one — so it follows the in-app
|
||||
# theme toggle (.dark on <html>), not the OS preference. If only `icon` is
|
||||
# attached, the same image is used in both modes. Caller must ensure at
|
||||
# least app.icon is attached; the monogram fallback handles no-icon.
|
||||
def app_icon_picture(app, class:, alt: nil)
|
||||
img_class = binding.local_variable_get(:class)
|
||||
alt ||= "#{app.name} icon"
|
||||
light = url_for(app.icon)
|
||||
dark = app.icon_dark.attached? ? url_for(app.icon_dark) : nil
|
||||
tag.picture do
|
||||
sources = []
|
||||
sources << tag.source(media: "(prefers-color-scheme: dark)", srcset: dark) if dark
|
||||
safe_join(sources + [image_tag(app.icon, class: img_class, alt: alt)])
|
||||
|
||||
if app.icon_dark.attached?
|
||||
safe_join([
|
||||
image_tag(app.icon, class: "#{img_class} dark:hidden", alt: alt),
|
||||
image_tag(app.icon_dark, class: "#{img_class} hidden dark:block", alt: alt)
|
||||
])
|
||||
else
|
||||
image_tag(app.icon, class: img_class, alt: alt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Clinch
|
||||
VERSION = "0.14.1"
|
||||
VERSION = "0.14.2"
|
||||
end
|
||||
|
||||
@@ -31,4 +31,23 @@ class ApplicationHelperTest < ActionView::TestCase
|
||||
# not a guarantee for all pairs, but should hold for at least one pair
|
||||
assert_not_equal monogram_color("Kavita"), monogram_color("Navidrome")
|
||||
end
|
||||
|
||||
test "app_icon_picture renders both icons with Tailwind dark: toggles when icon_dark is attached" do
|
||||
app = applications(:kavita_app)
|
||||
app.icon.attach(io: StringIO.new("light"), filename: "light.png", content_type: "image/png")
|
||||
app.icon_dark.attach(io: StringIO.new("dark"), filename: "dark.png", content_type: "image/png")
|
||||
|
||||
html = app_icon_picture(app, class: "h-10 w-10 rounded-lg")
|
||||
assert_match(/dark:hidden/, html)
|
||||
assert_match(/hidden dark:block/, html)
|
||||
end
|
||||
|
||||
test "app_icon_picture renders one img when no icon_dark is attached" do
|
||||
app = applications(:kavita_app)
|
||||
app.icon.attach(io: StringIO.new("light"), filename: "light.png", content_type: "image/png")
|
||||
|
||||
html = app_icon_picture(app, class: "h-10 w-10")
|
||||
refute_match(/dark:hidden/, html)
|
||||
refute_match(/hidden dark:block/, html)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user