Skip to content

Commit

Permalink
Add a theme selector to the backend UI
Browse files Browse the repository at this point in the history
- Save the user preference alongside the system preference so that
  when the system switches the UI will follow along.
- Use the session to store preferences so that we start the page
  with the correct theme(s).
- Keep the current theme in the select tag up to date at page load
  and whenever the system changes.

Co-Authored-By: piyushswain <[email protected]>
Co-Authored-By: Elia Schito <[email protected]>
Co-Authored-By: Massimiliano Lattanzio <[email protected]>
  • Loading branch information
3 people committed Jun 1, 2023
1 parent 2b9cba5 commit 4591402
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 1 deletion.
1 change: 1 addition & 0 deletions backend/app/assets/javascripts/spree/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
//= require spree/backend/images/index
//= require spree/backend/images/upload
//= require spree/backend/locale_selection
//= require spree/backend/theme_selection
//= require spree/backend/navigation
//= require spree/backend/option_type_autocomplete
//= require spree/backend/option_value_picker
Expand Down
36 changes: 36 additions & 0 deletions backend/app/assets/javascripts/spree/backend/theme_selection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Spree.ready(() => {
const themeSelect = document.querySelector(".js-theme-selection")
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)")
const lightTheme = themeSelect.dataset.selectedLightTheme
const darkTheme = themeSelect.dataset.selectedDarkTheme
const defaultTheme = themeSelect.dataset.defaultTheme

const updateSelection = () => {
console.log({
themeSelect,
prefersDark,
lightTheme,
darkTheme,
defaultTheme,
})
themeSelect.value = (prefersDark.matches ? darkTheme : lightTheme) || defaultTheme
}

const setTheme = () => {
Spree.ajax({
type: "PUT",
dataType: "json",
url: Spree.pathFor("admin/theme/set"),
data: {
switch_to_theme: themeSelect.value,
system_theme: prefersDark.matches ? "dark" : "light",
},
success: (data) => document.location.reload(),
})
}

updateSelection()

prefersDark.addEventListener("change", updateSelection)
themeSelect.addEventListener("change", setTheme)
})
30 changes: 30 additions & 0 deletions backend/app/controllers/spree/admin/theme_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

module Spree
module Admin
class ThemeController < Spree::Admin::BaseController
skip_before_action :authorize_admin, only: [:set]

def set
requested_theme = params[:switch_to_theme].presence

# 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)
session[session_key] = requested_theme
head :ok
else
head :not_found
end
end

private

def theme_is_available?(theme)
theme && Spree::Backend::Config.themes.key?(theme.to_sym)
end
end
end
end
3 changes: 2 additions & 1 deletion backend/app/views/spree/admin/shared/_head.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
<title><%= admin_page_title %></title>

<%= favicon_link_tag 'favicon.ico' %>
<%= stylesheet_link_tag Spree::Backend::Config.theme_path, media: 'all', data: {turbolinks_track: 'reload'} %>
<%= stylesheet_link_tag Spree::Backend::Config.theme_path(session[:admin_light_theme]), media: '(prefers-color-scheme: light)', data: {turbolinks_track: 'reload'} %>
<%= stylesheet_link_tag Spree::Backend::Config.theme_path(session[:admin_dark_theme]), media: '(prefers-color-scheme: dark)', data: {turbolinks_track: 'reload'} %>
<%= javascript_include_tag 'spree/backend/all', data: {turbolinks_track: 'reload'} %>
<%- if Rails.env.test? %>
Expand Down
1 change: 1 addition & 0 deletions backend/app/views/spree/admin/shared/_navigation.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<%= button_tag class: 'btn fa fa-chevron-circle-left', id: 'admin-nav-toggle', type: :button do %>
<span class="text"><%= t('spree.minimize_menu') %></span>
<% end %>
<%= render partial: 'spree/admin/shared/theme_selection' %>
<%= render partial: 'spree/admin/shared/locale_selection' %>
<% if lookup_context.exists?('spree/admin/shared/_navigation_footer') %>
<%= render partial: 'spree/admin/shared/navigation_footer' %>
Expand Down
13 changes: 13 additions & 0 deletions backend/app/views/spree/admin/shared/_theme_selection.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<label class="admin-navbar-selection">
<i class="fa fa-paint-brush fa-fw" title="<%= I18n.t('spree.choose_dashboard_theme') %>"></i>
<select
class="js-theme-selection custom-select fullwidth"
data-selected-light-theme="<%= session[:admin_light_theme] %>"
data-selected-dark-theme="<%= session[:admin_dark_theme] %>"
data-default-theme="<%= Spree::Backend::Config.theme %>"
>
<%= options_for_select(
Spree::Backend::Config.themes.keys.map { |theme| [theme.to_s.humanize, theme] }.sort,
) %>
</select>
</label>
1 change: 1 addition & 0 deletions backend/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
get '/search/products', to: "search#products", as: :search_products

put '/locale/set', to: 'locale#set', defaults: { format: :json }, as: :set_locale
put '/theme/set', to: 'theme#set', defaults: { format: :json }, as: :set_theme

resources :dashboards, only: [] do
collection do
Expand Down
32 changes: 32 additions & 0 deletions backend/spec/controllers/spree/admin/theme_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Spree::Admin::ThemeController, type: :controller do
stub_authorization!

it 'sets the theme in a different session key for each system theme' do
stub_spree_preferences(Spree::Backend::Config, themes: { foo: 'foo-path', bar: 'bar-path' })

get :set, params: { switch_to_theme: 'foo', system_theme: 'light', format: :json }

expect(session[:admin_light_theme]).to eq('foo')
expect(session[:admin_dark_theme]).to eq(nil)
expect(response).to have_http_status(:ok)

get :set, params: { switch_to_theme: 'bar', system_theme: 'dark', format: :json }
expect(session[:admin_light_theme]).to eq('foo')
expect(session[:admin_dark_theme]).to eq('bar')
expect(response).to have_http_status(:ok)
end

it 'responds with "not found" for a missing theme' do
stub_spree_preferences(Spree::Backend::Config, themes: { foo: 'foo-path' })

get :set, params: { switch_to_theme: 'bar', system_theme: 'dark', format: :json }

expect(session[:admin_light_theme]).to eq(nil)
expect(session[:admin_dark_theme]).to eq(nil)
expect(response).to have_http_status(:not_found)
end
end
1 change: 1 addition & 0 deletions core/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,7 @@ en:
choose_a_taxon_to_sort_products_for: Choose a taxon to sort products for
choose_currency: Choose Currency
choose_dashboard_locale: Choose Dashboard Locale
choose_dashboard_theme: Choose Dashboard Theme
choose_location: Choose Location
choose_promotion_action: Choose Action
choose_promotion_rule: Choose Rule
Expand Down

0 comments on commit 4591402

Please sign in to comment.