2 Commits

Author SHA1 Message Date
Dan Milne
0e9ec71013 Link the user show page from the admin users index
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled
CI / scan_container (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / system-test (push) Has been cancelled
The admin users index only exposed Edit / Delete actions per row, so
the Accessible-applications panel on the user show page was unreachable
without typing the URL by hand. Adds a View action and turns the email
into a link to the show page — mirroring how the applications and
groups indexes already work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-07 18:26:55 +10:00
Dan Milne
fe68f6e81e 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>
2026-06-07 17:19:36 +10:00
4 changed files with 36 additions and 12 deletions

View File

@@ -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

View File

@@ -61,7 +61,7 @@
<% @users.each do |user| %>
<tr>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 dark:text-gray-100 sm:pl-0">
<%= user.email_address %>
<%= link_to user.email_address, admin_user_path(user), class: "text-blue-600 hover:text-blue-900" %>
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500 dark:text-gray-400">
<% if user.status.present? %>
@@ -110,6 +110,7 @@
data: { turbo_method: :post },
class: "text-yellow-600 hover:text-yellow-900" %>
<% end %>
<%= link_to "View", admin_user_path(user), class: "text-blue-600 hover:text-blue-900" %>
<%= link_to "Edit", edit_admin_user_path(user), class: "text-blue-600 hover:text-blue-900" %>
<%= link_to "Delete", admin_user_path(user),
data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete this user?" },

View File

@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Clinch
VERSION = "0.14.1"
VERSION = "0.14.3"
end

View File

@@ -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