Темы в приложении Rails

Я хотел бы создать приложение Rails, которое позволяет пользователям вводить данные, а затем разрешать им изменять тему страницы. Таким образом, их данные могут быть оформлены по-разному на основе выбранной ими темы. Как я могу это сделать?

  • Изменить таблицу стилей?
  • Два отдельных вида с разными классами/элементами?
  • Динамически просто менять классы/идентификаторы/селектора?

Спасибо

Ответ 1

Самый простой способ разместить тему сайта - просто связать с другой таблицей стилей. Вы можете сделать это динамически, используя что-то вроде:

# in app/views/layouts/application.html.erb
<%= stylesheet_link_tag :application %>
<%= stylesheet_link_tag #{current_theme} %>

# in app/helpers/application_helper
def current_theme
  # You'll have to implement the logic for a user choosing a theme
  # and how to record that in the model.
  # Also, come up with a better name for your default theme, like 'twentyeleven' ;)
  current_user.theme || 'default'
end

Тогда у вас может быть пара манифестаций для тем. Например, каталог ваших ресурсов может выглядеть примерно так:

  • приложение/активы/таблицы стилей
    • application.css
    • buttons.css
    • theme1/
      • index.css
      • buttons.css
    • theme2/
      • index.css
      • buttons.css

Это поможет вам начать с чистой css-тематики. В какой-то момент вы, вероятно, захотите также их javascript и html-макеты. Когда вы начнете искать необходимость сделать что-то подобное в своем html:

<% if current_theme == 'theme1' %>
  <li>...
<% elsif current_theme == 'theme2' %>
  <b>...
<% end %>

тогда пришло время реализовать более надежную структуру тезисов:

  • namespace ваши html-шаблоны по темам (например, app/views/themes/theme1/users/index.html.erb) и визуализировать тематическую версию вместо стандартного
  • просто укажите частичные шаблоны (например, app/views/themes/theme1/users/_form.html.erb) и добавьте вспомогательный метод, например render_themed_partial
  • похож на приведенные выше подходы, но когда темы становятся очень большими, вы должны рассмотреть вопрос о том, чтобы поместить их в свои собственные драгоценные камни как двигатели рельсов.

Примечание. Это все для статических тем. Для динамических тем (например, когда администратор может входить в систему и редактировать таблицы стилей или html), вам нужно будет хранить информацию о контенте в базе данных. В зависимости от вашей архитектуры вы можете предоставить набор статических тем, а затем еще одну тему, которая динамически захватывает данные о стилях из базы данных. В этот момент вы разрабатываете CMS, однако, это выходит за рамки этого ответа:)

Ответ 2

Если мы создаем разные таблицы стилей для каждой темы и при небольших изменениях, нам необходимо внести одинаковые изменения во все стили. Это будет действительно боль в голове. Альтернативный способ - использовать концепции SASS (mixins).

Добавьте в свой Gemfile

gem 'sass-rails'

то

bundle install

Теперь вам нужно иметь свои стили CSS в одном файле SCSS. basic_styles.scss

$font_color: #565656;
$font-size: 13px;
$success-color: #088A08;
$error-color: #B40404;
@mixin basic_styles($dark_color,$light_color,$bullet_image) 
{
.footer
  {
    background-color: rgba($dark_color,0.9);
    color: $light_color;
    text-align: center;
    position: fixed;
    bottom:0;
    left:0;
    width: 100%;
    height: 15px;
    border-top: 1px solid lighten($dark_color, 9%);     
    padding-left: 10px;
    padding-right: 10px;       
    font-size: $font_size - 2; 
  }
  h3,hr,a,input
  {
    color: $dark_color;
  }
  h3
  {
    margin-top: 2px;
    margin-bottom: 2px;
  }
  hr {
    border-color: lighten($dark_color, 30%) -moz-use-text-color #FFFFFF;
    border-left: 0 none;
    border-right: 0 none;
    border-style: solid none;
    border-width: 1px 0;
  }
  .btn 
  {
    background-color: $dark_color;
    border-color: darken($dark_color, 15%);    
    border-radius: 4px 4px 4px 4px;
    border-style: solid;
    border-width: 1px;
    color: #FFFFFF;
    cursor: pointer;
    display: inline-block;
    line-height: 18px;
    padding: 3px 10px 3px 10px;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
    vertical-align: middle;
  }
  .btn:hover
  {
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
    -moz-box-shadow: 0px 0px 2px 1px lighten($dark_color, 10%);
    -webkit-box-shadow: 0px 0px 2px 1px lighten($dark_color, 10%);
    box-shadow: 0px 0px 2px 1px lighten($dark_color, 10%);
  }
  .success
  {
    color: $success-color;
  }
  .error
  {
    color: $error-color;
  }
}

Затем вы можете создать любое количество тем. Пример Тема_Blue.scss

@import "basic_styles";
$dark_color: #08c;
$light_color: #FFFFFF;
$bullet_image: 'bullet_blue.png';
@include basic_styles($dark_color,$light_color,$bullet_image);

Теперь в вашем html

<%= stylesheet_link_tag "Theme_Blue" %>

будет использовать все классы css, указанные в basic_styles.scss с синими цветами.

Вы можете добавить любое количество файлов тем, например Theme_Blue.scss. И измените на

<%= stylesheet_link_tag current_user.theme %>

Таким образом вам нужно изменить только basic_styles.scss для любых изменений.

Ответ 3

Мне удалось извлечь суть из ответа Chamnap (который почему-то не работал - возможно, версия Rails?).

class ApplicationController < ActionController::Base
  layout :layout_selector

  def layout_selector
    # puts "*** layout_selector #{session.to_json}"
    name = ['bootstrap', 'mytheme'][session[:theme].to_i] 
    # puts "*** loading theme #{name}"
    prepend_view_path "app/themes/#{name}/views"
    name
  end

Вы можете прочитать здесь:

Вам, вероятно, придется добавить путь к ресурсу и предварительно компилировать список (или использовать камень без использования метода theme).

  Dir.glob("#{Rails.root}/app/themes/*/assets/*").each do |dir|
    config.assets.paths << dir
  end

  config.assets.precompile += [ Proc.new { |path, fn| fn =~ /app\/themes/ && !%w(.js .css).include?(File.extname(path)) } ]
  config.assets.precompile += Dir["app/themes/*"].map { |path| "#{path.split('/').last}/all.js" }
  config.assets.precompile += Dir["app/themes/*"].map { |path| "#{path.split('/').last}/all.css" }

Не забудьте указать JS и изображения в подкаталогах с именем темы. Они могут быть раздельными на сервере, но в браузере и кеше, /images/logo.png выглядит одинаково для обеих тем. Поэтому вы должны использовать /images/theme1/logo.png и /images/theme2/logo.png.