diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 6f03231b7..59895d907 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -1,13 +1,16 @@ # frozen_string_literal: true class UserController < ApplicationController + include ThemeHelper include PaginatesAnswers - before_action :set_user + before_action :set_user, except: :show_theme before_action :hidden_social_graph_redirect, only: %i[followers followings] after_action :mark_notification_as_read, only: %i[show] def show + return show_theme if params[:format] == "css" + @pinned_answers = @user.answers.for_user(current_user).pinned.includes([{ user: :profile }, :question]).order(pinned_at: :desc).limit(10).load_async paginate_answers { |args| @user.cursored_answers(current_user_id: current_user, **args) } @@ -17,6 +20,16 @@ def show end end + def show_theme + theme = Theme.where(user: User.where("LOWER(screen_name) = ?", params[:username].downcase).select(:id)).first + return head :no_content unless theme + + expires_in 3.months + return if fresh_when theme, public: true + + render plain: get_theme_css(theme), content_type: "text/css" + end + def followers paginate_relationships(:cursored_follower_relationships) @users = @relationships.map(&:source) diff --git a/app/helpers/theme_helper.rb b/app/helpers/theme_helper.rb index 9cd04910f..7c54e05be 100644 --- a/app/helpers/theme_helper.rb +++ b/app/helpers/theme_helper.rb @@ -28,11 +28,7 @@ module ThemeHelper "muted_text" => "muted-text", }.freeze - def render_theme - theme = get_active_theme - - return unless theme - + def get_theme_css(theme) body = ":root {\n" theme.attributes.each do |k, v| @@ -42,9 +38,7 @@ def render_theme body += "\t--#{var}: #{get_color_for_key(var, v)};\n" end end - body += "\t--turbolinks-progress-color: ##{lighten(theme.primary_color)}\n}" - - content_tag(:style, body) + body + "\t--turbolinks-progress-color: ##{lighten(theme.primary_color)}\n}" end def get_color_for_key(key, color) @@ -58,7 +52,7 @@ def get_color_for_key(key, color) end def theme_color - theme = get_active_theme + theme = active_theme_user&.theme if theme theme.theme_color else @@ -67,7 +61,7 @@ def theme_color end def mobile_theme_color - theme = get_active_theme + theme = active_theme_user&.theme if theme theme.mobile_theme_color else @@ -75,32 +69,18 @@ def mobile_theme_color end end - def get_active_theme - if @user&.theme - if user_signed_in? - if current_user&.show_foreign_themes? - @user.theme - else - current_user&.theme - end - else - @user.theme - end - elsif @answer&.user&.theme - if user_signed_in? - if current_user&.show_foreign_themes? - @answer.user.theme - else - current_user&.theme - end - else - @answer.user.theme - end - elsif current_user&.theme - current_user.theme + def active_theme_user + user = @user || @answer&.user # rubocop:disable Rails/HelperInstanceVariable + + if user&.theme.present? && should_show_foreign_theme? + user + elsif user_signed_in? + current_user end end + def should_show_foreign_theme? = current_user&.show_foreign_themes || !user_signed_in? + def get_hex_color_from_theme_value(value) "0000000#{value.to_s(16)}"[-6, 6] end diff --git a/app/views/layouts/base.html.haml b/app/views/layouts/base.html.haml index cf829de8e..a563e1e06 100644 --- a/app/views/layouts/base.html.haml +++ b/app/views/layouts/base.html.haml @@ -5,20 +5,22 @@ %meta{ 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' } %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1, user-scalable=no, viewport-fit=cover' } - if user_signed_in? - %meta{ name: 'theme-color', content: theme_color, media: '(min-width: 993px)' } - %meta{ name: 'theme-color', content: mobile_theme_color, media: '(max-width: 992px)' } + %meta{ name: "theme-color", content: "var(--primary)", media: "(min-width: 993px)" } + %meta{ name: "theme-color", content: "var(--background)", media: "(max-width: 992px)" } - else - %meta{ name: 'theme-color', content: theme_color } + %meta{ name: "theme-color", content: "var(--primary)" } - if @user&.privacy_noindex? || @answer&.user&.privacy_noindex? || @question&.user&.privacy_noindex? %meta{ name: 'robots', content: 'noindex' } %link{ rel: 'manifest', href: '/manifest.json', crossorigin: 'use-credentials' } %link{ rel: 'apple-touch-icon', href: '/icons/maskable_icon_x192.png' } - %link{ rel: 'mask-icon', href: '/icons/icon.svg', color: theme_color } + %link{ rel: 'mask-icon', href: '/icons/icon.svg', color: "#5e35b1" } %link{ rel: 'icon', href: '/images/favicon/favicon-16.png', sizes: '16x16' } %link{ rel: 'icon', href: '/icons/maskable_icon_x192.png', sizes: '192x192' } %link{ rel: 'icon', href: '/images/favicon/favicon-32.png', sizes: '32x32' } %title= yield(:title) = stylesheet_link_tag "application", data: { 'turbo-track': "reload" }, media: "all" + - if active_theme_user.present? + %link{ rel: "stylesheet", href: user_path(username: active_theme_user.screen_name, format: "css"), data: { turbo_track: "reload" } } = javascript_include_tag 'application', data: { 'turbo-track': 'reload' }, defer: true = csrf_meta_tags = yield(:og) @@ -46,4 +48,3 @@ = `git rev-parse --short HEAD`.strip %p.text-danger Debug params: = debug params - = render_theme diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index b1d35574e..39a17469e 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -65,6 +65,58 @@ end end + describe "#show_theme" do + subject { get :show, params: { username: user.screen_name }, format: :css } + + context "user does not have a theme set" do + it "returns no content" do + expect(subject).to have_http_status(:no_content) + expect(response.body).to be_empty + end + end + + context "user has theme" do + let!(:theme) { FactoryBot.create(:theme, user:) } + + it "returns theme CSS" do + subject + expect(response).to have_http_status(:ok) + expect(response.body).to eq(<<~CSS.chomp) +:root { + --primary: #8e8cd8; + --primary-rgb: 142, 140, 216; + --primary-text: 255, 255, 255; + --danger: #d98b8b; + --danger-text: 255, 255, 255; + --success: #bfd98b; + --success-text: 255, 255, 255; + --warning: #d99e8b; + --warning-text: 255, 255, 255; + --info: #8bd9d9; + --info-text: 255, 255, 255; + --dark: #666666; + --dark-text: 238, 238, 238; + --raised-bg: #ffffff; + --raised-bg-rgb: 255, 255, 255; + --background: #c6c5eb; + --body-text: 51, 51, 51; + --muted-text: 51, 51, 51; + --input-bg: #f0edf4; + --input-text: 102, 102, 102; + --raised-accent: #f7f7f7; + --raised-accent-rgb: 247, 247, 247; + --light: #f8f9fa; + --light-text: 0, 0, 0; + --input-placeholder: 108, 117, 125; + --raised-text: 51, 51, 51; + --raised-accent-text: 51, 51, 51; + --turbolinks-progress-color: #ceccff +} + CSS + end + end + end + describe "#followers" do subject { get :followers, params: { username: user.screen_name } } diff --git a/spec/helpers/theme_helper_spec.rb b/spec/helpers/theme_helper_spec.rb index f7de94414..3476f3167 100644 --- a/spec/helpers/theme_helper_spec.rb +++ b/spec/helpers/theme_helper_spec.rb @@ -3,33 +3,6 @@ require "rails_helper" describe ThemeHelper, type: :helper do - describe "#render_theme" do - context "when target page doesn't have a theme" do - it "returns no theme" do - expect(helper.render_theme).to be_nil - end - end - - context "when target page has a theme" do - before(:each) do - @user = FactoryBot.create(:user) - @user.theme = Theme.new - @user.save! - end - - it "returns a theme" do - expect(helper.render_theme).to include("