Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[admin] dark mode #5511

Merged
merged 9 commits into from
Nov 15, 2023
12 changes: 12 additions & 0 deletions admin/app/assets/stylesheets/solidus_admin/dark.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* = require solidus_admin/tailwind.css
*/

html {
-webkit-filter: invert(100%);
filter: invert(100%) hue-rotate(180deg);
}

main img {
filter: invert(100%) hue-rotate(-180deg);
}
11 changes: 11 additions & 0 deletions admin/app/assets/stylesheets/solidus_admin/dimmed.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* = require solidus_admin/tailwind.css
*/

html {
filter: invert(91%) hue-rotate(180deg);
}

main img {
filter: invert(91%) brightness(1.5) contrast(1.5) hue-rotate(-180deg);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<details class="relative w-full" aria-label="<%= t('.account') %>">
<details
data-controller="details-click-outside"
class="relative w-full"
aria-label="<%= t('.account') %>"
<%= :open if params[:account_menu_open] %>
>
<summary
class="
flex gap-1.5
Expand All @@ -23,38 +28,41 @@

<% if (available_locales = Spree.i18n_available_locales).any? %>
<li class="h-8 flex items-center hover:bg-gray-25 rounded">
<%= form_tag request.fullpath, method: :get do %>
<label class="flex gap-2 items-center px-2">
<%= icon_tag("global-line", class: "w-full max-w-[20px] h-5 fill-current shrink") %>
<select class="w-full appearance-none grow bg-transparent outline-none" onchange="this.form.requestSubmit()" name="switch_to_locale">
<%= options_for_select(
available_locales
.map do |locale|
[
t(
"spree.i18n.this_file_language",
locale: locale,
default: locale.to_s,
fallback: false
),
locale
]
end
.sort,
selected: I18n.locale,
) %>
</select>
<%= icon_tag("expand-up-down-line", class: "w-full max-w-[20px] h-5 fill-current shrink") %>
</label>
<% end %>
<%= autosubmit_select_tag(
"switch_to_locale",
options_for_select(locale_options_for_select(available_locales), selected: I18n.locale),
icon: 'global-line',
) %>
</li>
<% end %>

<li class="h-8 items-center hover:bg-gray-25 rounded dark:hidden flex">
<%= autosubmit_select_tag(
"switch_to_theme",
options_for_select(theme_options_for_select, session[:admin_light_theme]),
icon: 'sun-line',
) do %>
<%= hidden_field_tag(:system_theme, :light) %>
<% end %>
</li>

<li class="h-8 items-center hover:bg-gray-25 rounded hidden dark:flex">
<%= autosubmit_select_tag(
"switch_to_theme",
options_for_select(theme_options_for_select, session[:admin_dark_theme]),
icon: 'moon-line',
) do %>
<%= hidden_field_tag(:system_theme, :dark) %>
<% end %>
</li>

<li class="h-8 flex items-center hover:bg-gray-25 rounded">
<%= link_to @account_path, class: 'flex gap-2 items-center px-2' do %>
<%= icon_tag("user-3-line", class: "w-5 h-5 fill-current shrink") %>
<span><%= t('.account') %></span>
<% end %>
</li>

<li class="h-8 flex items-center hover:bg-gray-25 rounded">
<%= button_to @logout_path, method: @logout_method, class: 'flex gap-2 items-center px-2' do %>
<%= icon_tag("logout-box-line", class: "w-5 h-5 fill-current shrink") %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,30 @@ def initialize(user_label:, account_path:, logout_path:, logout_method:)
@logout_path = logout_path
@logout_method = logout_method
end

def locale_options_for_select(available_locales)
available_locales.map do |locale|
[
t("spree.i18n.this_file_language", locale: locale, default: locale.to_s, fallback: false),
locale,
]
end.sort
end

def theme_options_for_select
SolidusAdmin::Config.themes.keys.map { |theme| [theme.to_s.humanize, theme] }.sort
end

def autosubmit_select_tag(name, options, icon:, &block)
form_tag(request.fullpath, method: :get, 'data-turbo': false, class: "w-full") do
safe_join([
block_given? ? capture(&block) : nil,
tag.label(safe_join([
icon_tag(icon, class: "w-full max-w-[20px] h-5 fill-current shrink"),
tag.select(options, name: name, onchange: "this.form.requestSubmit()", class: "w-full appearance-none grow bg-transparent outline-none"),
icon_tag("expand-up-down-line", class: "w-full max-w-[20px] h-5 fill-current shrink"),
]), class: "flex gap-2 items-center px-2"),
])
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class SolidusAdmin::Layout::Navigation::Item::Component < SolidusAdmin::BaseComponent
with_collection_parameter :item

# @param item [SolidusAdmin::MainNavItem
# @param item [SolidusAdmin::MainNavItem]
# @param fullpath [String] the current path
# @param url_helpers [#solidus_admin, #spree] context for generating paths
def initialize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ en:
customer: Customer
no_name: No name available
order_email: Order contact email
back: Back to orders
same_as_shipping: Same as shipping address

edit_email: "Edit order email"
Expand Down
1 change: 1 addition & 0 deletions admin/app/controllers/solidus_admin/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class BaseController < ApplicationController
include SolidusAdmin::ControllerHelpers::Authentication
include SolidusAdmin::ControllerHelpers::Authorization
include SolidusAdmin::ControllerHelpers::Locale
include SolidusAdmin::ControllerHelpers::Theme
include SolidusAdmin::ComponentsHelper
include SolidusAdmin::AuthenticationAdapters::Backend if defined?(Spree::Backend)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def update_user_locale
session[set_user_language_locale_key] = requested_locale

flash[:notice] = t('spree.locale_changed')
redirect_to url_for(request.params.except(:switch_to_locale))
redirect_to params.except(:switch_to_locale).permit!.to_h.merge(account_menu_open: true)
end
end

Expand All @@ -27,6 +27,6 @@ def user_locale
end

def set_locale
I18n.locale = user_locale
I18n.locale = I18n.locale_available?(user_locale) ? user_locale : I18n.default_locale
end
end
30 changes: 30 additions & 0 deletions admin/app/controllers/solidus_admin/controller_helpers/theme.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

module SolidusAdmin::ControllerHelpers::Theme
extend ActiveSupport::Concern

included do
before_action :update_user_theme
end

private

def update_user_theme
requested_theme = params[:switch_to_theme].presence or return

# Avoid interpolating user content into the session key
system_theme = params[:system_theme].presence == "dark" ? "dark" : "light"
session_key = :"admin_#{system_theme}_theme"

if theme_is_available?(requested_theme) && requested_theme.to_sym != session[session_key]
session[session_key] = requested_theme

flash[:notice] = t('spree.theme_changed')
redirect_to params.except(:switch_to_theme, :system_theme).permit!.to_h.merge(account_menu_open: true)
end
end

def theme_is_available?(theme)
theme && SolidusAdmin::Config.themes.key?(theme.to_sym)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Controller } from "@hotwired/stimulus"
import { useClickOutside } from "stimulus-use"

export default class extends Controller {
connect() {
useClickOutside(this)
}

clickOutside() {
this.element.removeAttribute("open")
}
}
6 changes: 4 additions & 2 deletions admin/app/views/layouts/solidus_admin/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
<head>
<%= favicon_link_tag 'solidus_admin/favicon.ico' %>
<title><%= solidus_admin_title %></title>
<%= stylesheet_link_tag "solidus_admin/application.css", "inter-font", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "inter-font", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag SolidusAdmin::Config.theme_path(session[:admin_light_theme]), media: '(prefers-color-scheme: light)', "data-turbo-track": "reload" %>
<%= stylesheet_link_tag SolidusAdmin::Config.theme_path(session[:admin_dark_theme]), media: '(prefers-color-scheme: dark)', "data-turbo-track": "reload" %>
<%= javascript_importmap_tags "solidus_admin/application", shim: false, importmap: SolidusAdmin.importmap %>
</head>

Expand All @@ -21,7 +23,7 @@
</main>
</div>

<div class="fixed inset-x-0 bottom-3 flex items-center justify-center flex-col gap-3" role="alert">
<div class="fixed inset-x-0 bottom-3 flex items-center justify-center flex-col gap-3 pointer-events-none" role="alert">
<% flash.each do |key, message| %>
<%= render component("ui/toast").new(text: message, scheme: key == :error ? :error : :default) %>
<% end %>
Expand Down
20 changes: 20 additions & 0 deletions admin/lib/solidus_admin/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,26 @@ def components

# The HTTP method used to logout the user in the admin interface.
preference :logout_link_method, :string, default: :delete

# @!attribute [rw] themes
# @return [Hash] A hash containing the themes that are available for the admin panel
preference :themes, :hash, default: {
solidus: 'solidus_admin/application',
solidus_dark: 'solidus_admin/dark',
solidus_dimmed: 'solidus_admin/dimmed',
}

# @!attribute [rw] theme
# @return [String] Default admin theme name
preference :theme, :string, default: 'solidus'

# @!attribute [rw] dark_theme
# @return [String] Default admin theme name
preference :dark_theme, :string, default: 'solidus_dark'

def theme_path(user_theme)
themes.fetch(user_theme&.to_sym, themes[theme.to_sym])
end
end
end

Expand Down
21 changes: 21 additions & 0 deletions admin/spec/features/accounts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,25 @@
expect(page).to have_content(user.email)
expect(current_path).to eq("/admin/users/#{user.id}/edit")
end

it "can change locale and theme", :js do
I18n.config.available_locales_set << :"en-UK"
I18n.config.available_locales_set << "en-UK"
I18n.backend.store_translations('en-UK', spree: { i18n: { this_file_language: "English (UK)" } })

user = create(:admin_user, email: '[email protected]')
stub_authorization! user
sign_in user

visit "/admin/products"
find('summary', text: user.email).click
expect(page).to have_content("English (US)")
select "English (UK)", from: "switch_to_locale"
expect(page).to have_content("English (UK)")
select "English (US)", from: 'switch_to_locale'
expect(page).to have_content("English (US)")

within('.dark\:hidden') { select "Solidus dark", from: "switch_to_theme" }
expect(page).to have_content("Solidus dark")
end
end
Loading