mirror of
https://github.com/Retrospring/retrospring.git
synced 2025-03-31 05:02:14 +02:00
Merge remote-tracking branch 'origin/feature-themes'
This commit is contained in:
commit
675ba646ea
25 changed files with 807 additions and 99 deletions
2
Gemfile
2
Gemfile
|
@ -39,6 +39,8 @@ gem 'fog'
|
||||||
gem 'fog-aws'
|
gem 'fog-aws'
|
||||||
gem 'momentjs-rails', '>= 2.9.0'
|
gem 'momentjs-rails', '>= 2.9.0'
|
||||||
gem 'bootstrap3-datetimepicker-rails', '~> 4.7.14'
|
gem 'bootstrap3-datetimepicker-rails', '~> 4.7.14'
|
||||||
|
gem 'tiny-color-rails'
|
||||||
|
gem 'jquery-minicolors-rails'
|
||||||
|
|
||||||
gem 'twemoji-rails'
|
gem 'twemoji-rails'
|
||||||
|
|
||||||
|
|
|
@ -231,6 +231,9 @@ GEM
|
||||||
jbuilder (2.2.13)
|
jbuilder (2.2.13)
|
||||||
activesupport (>= 3.0.0, < 5)
|
activesupport (>= 3.0.0, < 5)
|
||||||
multi_json (~> 1.2)
|
multi_json (~> 1.2)
|
||||||
|
jquery-minicolors-rails (2.1.4.0)
|
||||||
|
jquery-rails
|
||||||
|
rails (>= 3.2.8)
|
||||||
jquery-rails (4.0.3)
|
jquery-rails (4.0.3)
|
||||||
rails-dom-testing (~> 1.0)
|
rails-dom-testing (~> 1.0)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
|
@ -435,6 +438,8 @@ GEM
|
||||||
tilt (1.4.1)
|
tilt (1.4.1)
|
||||||
timers (4.0.1)
|
timers (4.0.1)
|
||||||
hitimes
|
hitimes
|
||||||
|
tiny-color-rails (0.0.2)
|
||||||
|
railties (>= 3.0)
|
||||||
tumblr_client (0.8.5)
|
tumblr_client (0.8.5)
|
||||||
faraday (~> 0.9.0)
|
faraday (~> 0.9.0)
|
||||||
faraday_middleware (~> 0.9.0)
|
faraday_middleware (~> 0.9.0)
|
||||||
|
@ -511,6 +516,7 @@ DEPENDENCIES
|
||||||
haml
|
haml
|
||||||
i18n-js
|
i18n-js
|
||||||
jbuilder (~> 2.2.4)
|
jbuilder (~> 2.2.4)
|
||||||
|
jquery-minicolors-rails
|
||||||
jquery-rails
|
jquery-rails
|
||||||
jquery-turbolinks
|
jquery-turbolinks
|
||||||
letter_opener
|
letter_opener
|
||||||
|
@ -545,6 +551,7 @@ DEPENDENCIES
|
||||||
spring (~> 1.3.5)
|
spring (~> 1.3.5)
|
||||||
sweetalert-rails
|
sweetalert-rails
|
||||||
thin
|
thin
|
||||||
|
tiny-color-rails
|
||||||
tumblr_client
|
tumblr_client
|
||||||
turbolinks
|
turbolinks
|
||||||
twemoji-rails
|
twemoji-rails
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#= require js.cookie
|
#= require js.cookie
|
||||||
#= require i18n
|
#= require i18n
|
||||||
#= require i18n/translations
|
#= require i18n/translations
|
||||||
|
#= require tinycolor-min
|
||||||
|
#= require jquery.minicolors
|
||||||
# local requires to be seen by everyone:
|
# local requires to be seen by everyone:
|
||||||
#= require_tree ./answerbox
|
#= require_tree ./answerbox
|
||||||
#= require_tree ./questionbox
|
#= require_tree ./questionbox
|
||||||
|
@ -28,6 +30,7 @@
|
||||||
#= require user
|
#= require user
|
||||||
#= require report
|
#= require report
|
||||||
#= require locale-box
|
#= require locale-box
|
||||||
|
#= require util
|
||||||
# not required:
|
# not required:
|
||||||
# _tree ./moderation
|
# _tree ./moderation
|
||||||
|
|
||||||
|
@ -62,9 +65,13 @@ _ready = ->
|
||||||
sweetAlertInitialize()
|
sweetAlertInitialize()
|
||||||
|
|
||||||
if document.getElementById('particles')?
|
if document.getElementById('particles')?
|
||||||
|
jumbo = $ '.j2-jumbo'
|
||||||
|
bodyColorOrig = jumbo.css 'background-color'
|
||||||
|
bodyColor = doppler 0.25, bodyColorOrig
|
||||||
|
console.log bodyColor, bodyColorOrig
|
||||||
particleground document.getElementById('particles'),
|
particleground document.getElementById('particles'),
|
||||||
dotColor: '#5e35b1'
|
dotColor: bodyColor
|
||||||
lineColor: '#5e35b1'
|
lineColor: bodyColor
|
||||||
|
|
||||||
if twemoji?
|
if twemoji?
|
||||||
twemoji.parse document.body,
|
twemoji.parse document.body,
|
||||||
|
|
|
@ -99,3 +99,57 @@ if window.URL? or window.webkitURL?
|
||||||
($ '#profile-header-crop-controls').slideDown()
|
($ '#profile-header-crop-controls').slideDown()
|
||||||
|
|
||||||
cropper.attr 'src', src
|
cropper.attr 'src', src
|
||||||
|
|
||||||
|
# theming
|
||||||
|
|
||||||
|
previewStyle = document.createElement 'style'
|
||||||
|
document.head.appendChild previewStyle
|
||||||
|
|
||||||
|
previewTimeout = null
|
||||||
|
|
||||||
|
previewTheme = ->
|
||||||
|
payload = {}
|
||||||
|
|
||||||
|
$('#update_theme').find('.color').each ->
|
||||||
|
n = this.name.substr 6, this.name.length - 7
|
||||||
|
payload[n] = parseInt this.value.substr(1, 6), 16
|
||||||
|
|
||||||
|
$.post '/settings/theme/preview.css', payload, (data) ->
|
||||||
|
previewStyle.innerHTML = data
|
||||||
|
, 'text'
|
||||||
|
|
||||||
|
null
|
||||||
|
|
||||||
|
themePresets = {
|
||||||
|
rs: [0x5E35B1, 0xFFFFFF, 0xFF0039, 0xFFFFFF, 0x3FB618, 0xFFFFFF, 0xFF7518, 0xFFFFFF, 0x9954BB, 0xFFFFFF, 0x222222, 0xEEEEEE, 0xF9F9F9, 0x151515, 0x5E35B1, 0xFFFFFF, 0x222222, 0xbbbbbb],
|
||||||
|
dc: [0x222222, 0xeeeeee, 0x222222, 0xeeeeee, 0x222222, 0xeeeeee, 0x222222, 0xeeeeee, 0x222222, 0xeeeeee, 0x222222, 0xeeeeee, 0x222222, 0xeeeeee, 0x111111, 0x555555, 0xeeeeee, 0xbbbbbb],
|
||||||
|
lc: [0xdddddd, 0x111111, 0xdddddd, 0x111111, 0xdddddd, 0x111111, 0xdddddd, 0x111111, 0xdddddd, 0x111111, 0xdddddd, 0x111111, 0xdddddd, 0x111111, 0xeeeeee, 0xaaaaaa, 0x111111, 0x444444]
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on 'submit', '#update_theme', (event) ->
|
||||||
|
$this = $ this
|
||||||
|
$this.find('.color').each ->
|
||||||
|
this.value = parseInt this.value.substr(1, 6), 16
|
||||||
|
true
|
||||||
|
|
||||||
|
$(document).ready ->
|
||||||
|
$('#update_theme .color').each ->
|
||||||
|
$this = $ this
|
||||||
|
this.value = '#' + ('000000' + parseInt(this.value).toString(16)).substr(-6, 6)
|
||||||
|
|
||||||
|
$this.minicolors
|
||||||
|
control: 'hue'
|
||||||
|
defaultValue: this.value
|
||||||
|
letterCase: 'lowercase'
|
||||||
|
position: 'bottom left'
|
||||||
|
theme: 'bootstrap'
|
||||||
|
inline: false
|
||||||
|
change: ->
|
||||||
|
clearTimeout previewTimeout
|
||||||
|
previewTimeout = setTimeout(previewTheme, 1000)
|
||||||
|
true
|
||||||
|
|
||||||
|
$(document).on 'click', 'a.theme_preset', (event) ->
|
||||||
|
preset = [].concat themePresets[this.dataset.preset]
|
||||||
|
$('#update_theme .color').each ->
|
||||||
|
$(this).minicolors 'value', '#' + ('000000' + parseInt(preset.shift()).toString(16)).substr(-6, 6)
|
||||||
|
|
21
app/assets/javascripts/util.coffee
Normal file
21
app/assets/javascripts/util.coffee
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
window.doppler = (percentage, value, relative = false) ->
|
||||||
|
while percentage >= 1
|
||||||
|
percentage /= 10
|
||||||
|
tc_color = tinycolor(value).toRgb()
|
||||||
|
color = [tc_color.r, tc_color.g, tc_color.b]
|
||||||
|
if relative
|
||||||
|
for _c, i in color
|
||||||
|
x = (255 - color[i]) * percentage
|
||||||
|
if x == 0
|
||||||
|
x = color[i] * percentage
|
||||||
|
color[i] -= x
|
||||||
|
else
|
||||||
|
color[i] += x
|
||||||
|
else
|
||||||
|
adj = 255 * percentage
|
||||||
|
for _c, i in color
|
||||||
|
if color[i] + adj > 255
|
||||||
|
color[i] -= adj
|
||||||
|
else
|
||||||
|
color[i] += adj
|
||||||
|
'#' + color.map((x) -> Math.floor(Math.max(0, Math.min(255, x))).toString(16)).join ''
|
|
@ -3,6 +3,7 @@
|
||||||
*= require growl
|
*= require growl
|
||||||
*= require jquery.guillotine
|
*= require jquery.guillotine
|
||||||
*= require sweet-alert
|
*= require sweet-alert
|
||||||
|
*= require jquery.minicolors
|
||||||
*= require flags
|
*= require flags
|
||||||
*= require_self
|
*= require_self
|
||||||
*/
|
*/
|
||||||
|
@ -63,3 +64,11 @@ body { padding-top: $navbar-height; }
|
||||||
$nprogress-color: lighten($navbar-inverse-bg, 25%);
|
$nprogress-color: lighten($navbar-inverse-bg, 25%);
|
||||||
@import 'nprogress';
|
@import 'nprogress';
|
||||||
@import 'nprogress-bootstrap';
|
@import 'nprogress-bootstrap';
|
||||||
|
|
||||||
|
.minicolors-theme-bootstrap .minicolors-swatch {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
class UserController < ApplicationController
|
class UserController < ApplicationController
|
||||||
|
include ThemeHelper
|
||||||
|
|
||||||
before_filter :authenticate_user!, only: %w(edit update edit_privacy update_privacy data)
|
before_filter :authenticate_user!, only: %w(edit update edit_privacy update_privacy data)
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -25,7 +27,7 @@ class UserController < ApplicationController
|
||||||
|
|
||||||
def update
|
def update
|
||||||
user_attributes = params.require(:user).permit(:display_name, :profile_picture, :profile_header, :motivation_header, :website,
|
user_attributes = params.require(:user).permit(:display_name, :profile_picture, :profile_header, :motivation_header, :website,
|
||||||
:location, :bio, :crop_x, :crop_y, :crop_w, :crop_h, :crop_h_x, :crop_h_y, :crop_h_w, :crop_h_h)
|
:location, :bio, :crop_x, :crop_y, :crop_w, :crop_h, :crop_h_x, :crop_h_y, :crop_h_w, :crop_h_h, :show_foreign_themes)
|
||||||
if current_user.update_attributes(user_attributes)
|
if current_user.update_attributes(user_attributes)
|
||||||
text = t('flash.user.update.text')
|
text = t('flash.user.update.text')
|
||||||
text += t('flash.user.update.avatar') if user_attributes[:profile_picture]
|
text += t('flash.user.update.avatar') if user_attributes[:profile_picture]
|
||||||
|
@ -91,4 +93,58 @@ class UserController < ApplicationController
|
||||||
|
|
||||||
def data
|
def data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def edit_theme
|
||||||
|
end
|
||||||
|
|
||||||
|
# NOTE: Yes, I am storing and transmitting values as 3 byte numbers because false sense of security.
|
||||||
|
def preview_theme
|
||||||
|
attrib = params.permit([
|
||||||
|
:primary_color, :primary_text,
|
||||||
|
:danger_color, :danger_text,
|
||||||
|
:success_color, :success_text,
|
||||||
|
:warning_color, :warning_text,
|
||||||
|
:info_color, :info_text,
|
||||||
|
:default_color, :default_text,
|
||||||
|
:panel_color, :panel_text,
|
||||||
|
:link_color, :background_color,
|
||||||
|
:background_text, :background_muted
|
||||||
|
])
|
||||||
|
|
||||||
|
attrib.each do |k ,v|
|
||||||
|
attrib[k] = v.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
render plain: render_theme_with_context(attrib)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_theme
|
||||||
|
update_attributes = params.require(:theme).permit([
|
||||||
|
:primary_color, :primary_text,
|
||||||
|
:danger_color, :danger_text,
|
||||||
|
:success_color, :success_text,
|
||||||
|
:warning_color, :warning_text,
|
||||||
|
:info_color, :info_text,
|
||||||
|
:default_color, :default_text,
|
||||||
|
:panel_color, :panel_text,
|
||||||
|
:link_color, :background_color,
|
||||||
|
:background_text, :background_muted
|
||||||
|
])
|
||||||
|
|
||||||
|
if current_user.theme.nil?
|
||||||
|
current_user.theme = Theme.new update_attributes
|
||||||
|
current_user.theme.user_id = current_user.id
|
||||||
|
|
||||||
|
if current_user.theme.save
|
||||||
|
flash[:success] = 'Theme saved.'
|
||||||
|
else
|
||||||
|
flash[:error] = 'Theme saving failed.'
|
||||||
|
end
|
||||||
|
elsif current_user.theme.update_attributes(update_attributes)
|
||||||
|
flash[:success] = 'Theme saved.'
|
||||||
|
else
|
||||||
|
flash[:error] = 'Theme saving failed.'
|
||||||
|
end
|
||||||
|
redirect_to edit_user_theme_path
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
50
app/helpers/theme_helper.rb
Normal file
50
app/helpers/theme_helper.rb
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
module ThemeHelper
|
||||||
|
def render_theme_with_context(context = {})
|
||||||
|
klass = Class.new do
|
||||||
|
def initialize(hash = {})
|
||||||
|
if hash.is_a? ActiveRecord::Base
|
||||||
|
x = [:primary_color, :primary_text,
|
||||||
|
:danger_color, :danger_text,
|
||||||
|
:success_color, :success_text,
|
||||||
|
:warning_color, :warning_text,
|
||||||
|
:info_color, :info_text,
|
||||||
|
:default_color, :default_text,
|
||||||
|
:panel_color, :panel_text,
|
||||||
|
:link_color, :background_color,
|
||||||
|
:background_text, :background_muted]
|
||||||
|
|
||||||
|
x.each do |v|
|
||||||
|
next if hash[v].nil?
|
||||||
|
self.instance_variable_set "@#{v}", ('#' + ('0000000' + hash[v].to_s(16))[-6, 6])
|
||||||
|
end
|
||||||
|
elsif hash.is_a? Hash
|
||||||
|
hash.each do |k, v|
|
||||||
|
next unless v.is_a? Fixnum
|
||||||
|
|
||||||
|
self.instance_variable_set "@#{k}", ('#' + ('0000000' + hash[k].to_s(16))[-6, 6])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render
|
||||||
|
style = if Rails.env == 'production'
|
||||||
|
:compressed
|
||||||
|
else
|
||||||
|
:compact
|
||||||
|
end.freeze
|
||||||
|
|
||||||
|
css = if $__THEME_CSS_CACHE_V1.nil?
|
||||||
|
File.read Rails.root.join 'app/views/user/theme.css.scss.erb'
|
||||||
|
else
|
||||||
|
$__THEME_CSS_CACHE_V1
|
||||||
|
end
|
||||||
|
|
||||||
|
erb = ERB.new css
|
||||||
|
sass = Sass::Engine.new erb.result(binding), style: style, cache: false, load_paths: [], syntax: :scss
|
||||||
|
return sass.render.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return klass.new(context).render
|
||||||
|
end
|
||||||
|
end
|
35
app/models/theme.rb
Normal file
35
app/models/theme.rb
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
class Theme < ActiveRecord::Base
|
||||||
|
include ThemeHelper
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
|
||||||
|
validates_numericality_of :primary_color, :primary_text,
|
||||||
|
:danger_color, :danger_text,
|
||||||
|
:success_color, :success_text,
|
||||||
|
:warning_color, :warning_text,
|
||||||
|
:info_color, :info_text,
|
||||||
|
:default_color, :default_text,
|
||||||
|
:panel_color, :panel_text,
|
||||||
|
:link_color, :background_color,
|
||||||
|
:background_text, :background_muted,
|
||||||
|
greater_than_or_equal_to: 0, less_than_or_equal_to: 0xFFFFFF,
|
||||||
|
allow_nil: true, only_integer: true
|
||||||
|
|
||||||
|
has_attached_file :css, use_timestamp: false
|
||||||
|
validates_attachment_content_type :css, content_type: 'text/x-c'
|
||||||
|
|
||||||
|
before_save do
|
||||||
|
self.css = nil
|
||||||
|
|
||||||
|
style = StringIO.new(render_theme_with_context(self))
|
||||||
|
|
||||||
|
style.class.class_eval {
|
||||||
|
attr_accessor :original_filename, :content_type
|
||||||
|
}
|
||||||
|
|
||||||
|
style.content_type = 'text/x-c'
|
||||||
|
style.original_filename = 'theme.css'
|
||||||
|
|
||||||
|
self.css = style
|
||||||
|
end
|
||||||
|
end
|
|
@ -31,6 +31,8 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
has_many :subscriptions, dependent: :destroy
|
has_many :subscriptions, dependent: :destroy
|
||||||
|
|
||||||
|
has_one :theme, dependent: :destroy
|
||||||
|
|
||||||
SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/
|
SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/
|
||||||
WEBSITE_REGEX = /https?:\/\/([A-Za-z.\-]+)\/?(?:.*)/i
|
WEBSITE_REGEX = /https?:\/\/([A-Za-z.\-]+)\/?(?:.*)/i
|
||||||
|
|
||||||
|
|
|
@ -12,26 +12,32 @@
|
||||||
%title= yield(:title)
|
%title= yield(:title)
|
||||||
= javascript_include_tag 'i18n', 'data-turbolinks-track' => true
|
= javascript_include_tag 'i18n', 'data-turbolinks-track' => true
|
||||||
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
|
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
|
||||||
|
- if @user.present? and @user.theme.present? and (user_signed_in? and current_user.show_foreign_themes?)
|
||||||
|
%link{rel: 'stylesheet', href: @user.theme.css.url, media: :all, 'data-turbolinks-track' => true}
|
||||||
|
- elsif user_signed_in? and current_user.theme.present?
|
||||||
|
%link{rel: 'stylesheet', href: current_user.theme.css.url, media: :all, 'data-turbolinks-track' => true}
|
||||||
|
- else
|
||||||
= javascript_include_tag 'application', 'data-turbolinks-track' => true
|
= javascript_include_tag 'application', 'data-turbolinks-track' => true
|
||||||
- if user_signed_in?
|
- if user_signed_in?
|
||||||
- if current_user.mod?
|
- if current_user.mod?
|
||||||
= javascript_include_tag 'moderation', 'data-turbolinks-track' => true
|
= javascript_include_tag 'moderation', 'data-turbolinks-track' => true
|
||||||
= csrf_meta_tags
|
= csrf_meta_tags
|
||||||
%body
|
%body#version1
|
||||||
= render 'layouts/header'
|
= render 'layouts/header'
|
||||||
= yield
|
= yield
|
||||||
= render 'shared/locales'
|
= render 'shared/locales'
|
||||||
- if Rails.env.development?
|
- if Rails.env.development?
|
||||||
%hr
|
#debug
|
||||||
.container
|
%hr
|
||||||
%p
|
.container
|
||||||
Current branch:
|
%p
|
||||||
%code= `git rev-parse --abbrev-ref HEAD`
|
Current branch:
|
||||||
(commit
|
%code= `git rev-parse --abbrev-ref HEAD`
|
||||||
= succeed ')' do
|
(commit
|
||||||
= `git rev-parse --short HEAD`.strip
|
= succeed ')' do
|
||||||
%p.text-danger Debug params:
|
= `git rev-parse --short HEAD`.strip
|
||||||
= debug params
|
%p.text-danger Debug params:
|
||||||
|
= debug params
|
||||||
- if Rails.env.production?
|
- if Rails.env.production?
|
||||||
%noscript
|
%noscript
|
||||||
%p
|
%p
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
- header_class = if user.profile_header.exists? then "userbox--header-container" else "userbox--no-header" end
|
||||||
.panel.panel-default
|
.panel.panel-default
|
||||||
%img.userbox--header{src: user.profile_header.url(:mobile)}
|
%div{class: header_class}
|
||||||
|
%img.userbox--header{src: user.profile_header.url(:mobile)}
|
||||||
.panel-body
|
.panel-body
|
||||||
%img.userbox--avatar{src: user.profile_picture.url(:small)}
|
%img.userbox--avatar{src: user.profile_picture.url(:small)}
|
||||||
%p.userbox--username
|
%p.userbox--username
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
- header_class = if current_user.profile_header.exists? then "userbox--header-container" else "userbox--no-header" end
|
||||||
.panel.panel-default.hidden-xs
|
.panel.panel-default.hidden-xs
|
||||||
%img.userbox--header{src: current_user.profile_header.url(:mobile)}
|
%div{class: header_class}
|
||||||
|
%img.userbox--header{src: current_user.profile_header.url(:mobile)}
|
||||||
.panel-body
|
.panel-body
|
||||||
%img.userbox--avatar{src: current_user.profile_picture.url(:small)}
|
%img.userbox--avatar{src: current_user.profile_picture.url(:small)}
|
||||||
%p.userbox--username
|
%p.userbox--username
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
- type ||= @type || :nil
|
- type ||= @type || :nil
|
||||||
|
- header_class = if user.profile_header.exists? then "userbox--header-container" else "userbox--no-header" end
|
||||||
.panel.panel-default
|
.panel.panel-default
|
||||||
%img.userbox--header{src: user.profile_header.url(:mobile)}
|
%div{class: header_class}
|
||||||
|
%img.userbox--header{src: user.profile_header.url(:mobile)}
|
||||||
.panel-body
|
.panel-body
|
||||||
%img.userbox--avatar{src: user.profile_picture.url(:small)}
|
%img.userbox--avatar{src: user.profile_picture.url(:small)}
|
||||||
%p.userbox--username
|
%p.userbox--username
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
= list_group_item t('views.settings.tabs.profile'), edit_user_profile_path
|
= list_group_item t('views.settings.tabs.profile'), edit_user_profile_path
|
||||||
= list_group_item t('views.settings.tabs.privacy'), edit_user_privacy_path
|
= list_group_item t('views.settings.tabs.privacy'), edit_user_privacy_path
|
||||||
= list_group_item t('views.settings.tabs.sharing'), services_path
|
= list_group_item t('views.settings.tabs.sharing'), services_path
|
||||||
|
= list_group_item 'Theme', edit_user_theme_path
|
||||||
= list_group_item "Your Data", user_data_path
|
= list_group_item "Your Data", user_data_path
|
||||||
|
|
||||||
.hidden-xs= render "shared/links"
|
.hidden-xs= render "shared/links"
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
|
|
||||||
= f.text_area :bio, label: t('views.settings.profile.bio'), placeholder: t('views.settings.profile.placeholder.bio')
|
= f.text_area :bio, label: t('views.settings.profile.bio'), placeholder: t('views.settings.profile.placeholder.bio')
|
||||||
|
|
||||||
|
= f.check_box :show_foreign_themes, label: 'Render other user themes when visiting their profile'
|
||||||
|
|
||||||
- for attrib in %i(crop_x crop_y crop_w crop_h)
|
- for attrib in %i(crop_x crop_y crop_w crop_h)
|
||||||
= f.hidden_field attrib, id: attrib
|
= f.hidden_field attrib, id: attrib
|
||||||
|
|
||||||
|
|
59
app/views/user/edit_theme.html.haml
Normal file
59
app/views/user/edit_theme.html.haml
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
- provide(:title, generate_title("Theme Settings"))
|
||||||
|
.container.j2-page
|
||||||
|
= render 'settings_tabs'
|
||||||
|
.col-md-9.col-xs-12.col-sm-9
|
||||||
|
= render 'layouts/messages'
|
||||||
|
.panel.panel-default
|
||||||
|
.panel-body
|
||||||
|
%b Presets:
|
||||||
|
%a{href: '#', class: 'theme_preset', data: {preset: 'rs'}} Retrospring Purple,
|
||||||
|
%a{href: '#', class: 'theme_preset', data: {preset: 'dc'}} Dark Copycat,
|
||||||
|
%a{href: '#', class: 'theme_preset', data: {preset: 'lc'}} Light Copycat
|
||||||
|
= bootstrap_form_for(current_user.theme || Theme.new, url: {action: "update_theme"}, html: {id: 'update_theme'}, method: "patch") do |f|
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :primary_color, class: 'color', data: {default: 0x5E35B1}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :primary_text, class: 'color', data: {default: 0xFFFFFF}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :danger_color, class: 'color', data: {default: 0xFF0039}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :danger_text, class: 'color', data: {default: 0xFFFFFF}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :success_color, class: 'color', data: {default: 0x3FB618}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :success_text, class: 'color', data: {default: 0xFFFFFF}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :warning_color, class: 'color', data: {default: 0xFF7518}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :warning_text, class: 'color', data: {default: 0xFFFFFF}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :info_color, class: 'color', data: {default: 0x9954BB}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :info_text, class: 'color', data: {default: 0xFFFFFF}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :default_color, class: 'color', data: {default: 0x222222}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :default_text, class: 'color', data: {default: 0xEEEEEE}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :panel_color, class: 'color', data: {default: 0xF9F9F9}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :panel_text, class: 'color', data: {default: 0x151515}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :link_color, class: 'color', data: {default: 0x5E35B1}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :background_color, class: 'color', data: {default: 0xFFFFFF}
|
||||||
|
.row
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :background_text, class: 'color', data: {default: 0x222222}
|
||||||
|
.col-md-6
|
||||||
|
= f.text_field :background_muted, class: 'color', data: {default: 0xBBBBBB}
|
||||||
|
|
||||||
|
= f.submit t('views.actions.save'), class: 'btn btn-primary'
|
388
app/views/user/theme.css.scss.erb
Normal file
388
app/views/user/theme.css.scss.erb
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
// LEGEND
|
||||||
|
|
||||||
|
// TYPE_COLOR: BACKGROUND COLOR
|
||||||
|
// TYPE_BORDER: BORDER COLOR
|
||||||
|
// TYPE_TEXT: TEXT COLOR
|
||||||
|
|
||||||
|
// PRIMARY COLOR
|
||||||
|
|
||||||
|
$primary_color: <%= @primary_color || "#5e35b1" %>;
|
||||||
|
$primary_border: darken(adjust-hue($primary_color, -10), 5%);
|
||||||
|
$primary_text: <%= @primary_text || "white" %>;
|
||||||
|
|
||||||
|
// DANGER COLOR
|
||||||
|
$danger_color: <%= @danger_color || "#FF0039" %>;
|
||||||
|
$danger_border: darken(adjust-hue($danger_color, -10), 5%);
|
||||||
|
$danger_text: <%= @danger_text || "white" %>;
|
||||||
|
|
||||||
|
// SUCCESS COLOR
|
||||||
|
|
||||||
|
$success_color: <%= @success_color || "#3FB618" %>;
|
||||||
|
$success_border: darken(adjust-hue($success_color, -10), 5%);
|
||||||
|
$success_text: <%= @success_text || "white" %>;
|
||||||
|
|
||||||
|
// WARNING COLOR
|
||||||
|
|
||||||
|
$warning_color: <%= @warning_color || "#FF7518" %>;
|
||||||
|
$warning_border: darken(adjust-hue($warning_color, -10), 5%);
|
||||||
|
$warning_text: <%= @warning_text || "white" %>;
|
||||||
|
|
||||||
|
// INFO COLOR
|
||||||
|
|
||||||
|
$info_color: <%= @info_color || "#9954BB" %>;
|
||||||
|
$info_border: darken(adjust-hue($info_color, -10), 5%);
|
||||||
|
$info_text: <%= @info_text || "white" %>;
|
||||||
|
|
||||||
|
// DEFAULT COLOR
|
||||||
|
|
||||||
|
$default_color: <%= @default_color || "#222222" %>;
|
||||||
|
$default_border: darken(adjust-hue($default_color, -10), 5%);
|
||||||
|
$default_text: <%= @default_text || "#eeeeee" %>;
|
||||||
|
|
||||||
|
// PANEL COLOR
|
||||||
|
|
||||||
|
$panel_color: <%= @panel_color || "#F9F9F9" %>;
|
||||||
|
$panel_border: darken(adjust-hue($panel_color, -10), 5%);
|
||||||
|
$panel_text: <%= @panel_text || "#151515" %>;
|
||||||
|
|
||||||
|
// AUXILIARY COLOR
|
||||||
|
|
||||||
|
$link_color: <%= @link_color || "#5E35B1" %>;
|
||||||
|
$background_color: <%= @background_color || "#ffffff" %>;
|
||||||
|
$background_text: <%= @background_text || "#222222" %>;
|
||||||
|
$background_muted: <%= @background_muted || "#bbbbbb" %>;
|
||||||
|
|
||||||
|
body#version1 {
|
||||||
|
a, {
|
||||||
|
&, &:hover, &:active {
|
||||||
|
color: $link_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr, .locales #locales-panel ul {
|
||||||
|
border-color: $link_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
background-color: $background_color;
|
||||||
|
color: $background_text;
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
|
||||||
|
nav.navbar {
|
||||||
|
|
||||||
|
// Nav Dropdown
|
||||||
|
|
||||||
|
&, .dropdown-menu {
|
||||||
|
background-color: $primary_color;
|
||||||
|
border-color: $primary_border;
|
||||||
|
border-top: none;
|
||||||
|
|
||||||
|
color: $primary_text;
|
||||||
|
|
||||||
|
.media, .dropdown-header {
|
||||||
|
color: $primary_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
> li.divider {
|
||||||
|
background-color: $primary_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
> li {
|
||||||
|
> a:hover {
|
||||||
|
background-color: mix($primary_color, $primary_text, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
&, &:hover, &:active {
|
||||||
|
color: $primary_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav > li > .btn > i {
|
||||||
|
color: $primary_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav Links
|
||||||
|
|
||||||
|
a {
|
||||||
|
&, &:hover, &:active {
|
||||||
|
color: $primary_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:not(.profile--image-dropdown):before {
|
||||||
|
background-color: $primary_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
|
||||||
|
.media, #notifications .list-group-item {
|
||||||
|
color: $panel_text;
|
||||||
|
background: $panel_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
|
||||||
|
.j2-jumbo {
|
||||||
|
background-color: $primary_color;
|
||||||
|
border-color: $primary_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
#profile--header.profile--no-header:before, .userbox--no-header:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: $primary_color;
|
||||||
|
|
||||||
|
img {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.userbox--no-header, .panel-body {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panels, and modals
|
||||||
|
|
||||||
|
.panel, .modal-dialog {
|
||||||
|
border-color: $panel_border;
|
||||||
|
|
||||||
|
.panel-heading, .panel-footer, .panel-body, .modal-header, .modal-footer, .modal-body, .modal-content {
|
||||||
|
color: $panel_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a:hover, a:active {
|
||||||
|
color: $panel_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answerbox--question-user, .answerbox--question-text, .answerbox--answer-user, .answerbox--answer-text {
|
||||||
|
color: $panel_text;
|
||||||
|
|
||||||
|
&.text-muted {
|
||||||
|
color: mix($panel_text, $background_muted, 70%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
background-color: $panel_color;
|
||||||
|
border-color: $panel_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-addon {
|
||||||
|
background: $panel_color;
|
||||||
|
border: $panel_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&, .panel-heading, .panel-footer, .modal-header, .modal-footer {
|
||||||
|
background-color: mix($panel_color, $panel_text, 90%);
|
||||||
|
border-color: mix($panel_color, $panel_text, 85%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-body, .modal-body, .modal-content {
|
||||||
|
background-color: $panel_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-navigation dropdowns
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
background-color: $panel_color;
|
||||||
|
border-color: $panel_border;
|
||||||
|
color: $panel_text;
|
||||||
|
|
||||||
|
> li.divider {
|
||||||
|
background-color: $panel_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
> li {
|
||||||
|
> a:hover {
|
||||||
|
background-color: mix($panel_color, $panel_text, 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
&, &:hover, &:active {
|
||||||
|
color: $panel_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-muted {
|
||||||
|
color: $background_muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
.nav-tabs {
|
||||||
|
border-color: transparent;
|
||||||
|
margin-top: -1px;
|
||||||
|
|
||||||
|
li.active a, li:active a, li:hover a {
|
||||||
|
background: mix($panel_color, $panel_text, 90%);
|
||||||
|
color: mix($panel_text, $panel_color, 90%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
|
||||||
|
.list-group .list-group-item {
|
||||||
|
background-color: $panel_color;
|
||||||
|
color: $panel_text;
|
||||||
|
border-color: $panel_border;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
background-color: $panel_text;
|
||||||
|
border-color: $panel_border;
|
||||||
|
color: $panel_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active, &:hover {
|
||||||
|
background-color: $primary_color;
|
||||||
|
color: $primary_text;
|
||||||
|
border-color: $primary_border;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
background-color: $primary_text;
|
||||||
|
border-color: $primary_border;
|
||||||
|
color: $primary_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buttons, Alerts, Labels, Panel Badges, Badges, List Items
|
||||||
|
|
||||||
|
.btn-primary, .alert-primary, .label-primary, .panel-badge-primary, .badge-primary, .list-group-item-primary {
|
||||||
|
color: $primary_text !important;
|
||||||
|
background-color: $primary_color !important;
|
||||||
|
border-color: $primary_border !important;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: $primary_color !important;
|
||||||
|
background-color: $primary_text !important;
|
||||||
|
border-color: $primary_border !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: mix($primary_color, $primary_text, 90%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger, .alert-danger, .label-danger, .panel-badge-danger, .badge-danger, .list-group-item-danger {
|
||||||
|
color: $danger_text !important;
|
||||||
|
background-color: $danger_color !important;
|
||||||
|
border-color: $danger_border !important;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: $danger_color !important;
|
||||||
|
background-color: $danger_text !important;
|
||||||
|
border-color: $danger_border !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover {
|
||||||
|
background-color: mix($danger_color, $danger_text, 90%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success, .alert-success, .label-success, .panel-badge-success, .badge-success, .list-group-item-success {
|
||||||
|
color: $success_text !important;
|
||||||
|
background-color: $success_color !important;
|
||||||
|
border-color: $success_border !important;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: $success_color !important;
|
||||||
|
background-color: $success_text !important;
|
||||||
|
border-color: $success_border !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success:hover {
|
||||||
|
background-color: mix($success_color, $success_text, 90%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning, .alert-warning, .label-warning, .panel-badge-warning, .badge-warning, .list-group-item-warning {
|
||||||
|
color: $warning_text !important;
|
||||||
|
background-color: $warning_color !important;
|
||||||
|
border-color: $warning_border !important;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: $warning_color !important;
|
||||||
|
background-color: $warning_text !important;
|
||||||
|
border-color: $warning_border !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning:hover {
|
||||||
|
background-color: mix($warning_color, $warning_text, 90%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-info, .alert-info, .label-info, .panel-badge-info, .badge-info, .list-group-item-info {
|
||||||
|
color: $info_text !important;
|
||||||
|
background-color: $info_color !important;
|
||||||
|
border-color: $info_border !important;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: $info_color !important;
|
||||||
|
background-color: $info_text !important;
|
||||||
|
border-color: $info_border !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-info:hover {
|
||||||
|
background-color: mix($info_color, $info_text, 90%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-default, .alert-default, .label-default, .panel-badge-default, .badge-default, .list-group-item-default {
|
||||||
|
color: $default_text !important;
|
||||||
|
background-color: $default_color !important;
|
||||||
|
border-color: $default_border !important;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: $default_color !important;
|
||||||
|
background-color: $default_text !important;
|
||||||
|
border-color: $default_border !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-default:hover {
|
||||||
|
background-color: mix($default_color, $default_text, 90%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset debug
|
||||||
|
#debug {
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: inherit;
|
||||||
|
border-color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* nprogress */
|
||||||
|
$nprogress-color: lighten($primary_color, 25%);
|
||||||
|
|
||||||
|
#nprogress {
|
||||||
|
.bar {
|
||||||
|
background: $nprogress-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.peg {
|
||||||
|
box-shadow: 0 0 10px $nprogress-color, 0 0 5px $nprogress-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner-icon {
|
||||||
|
border-top-color: $nprogress-color;
|
||||||
|
border-left-color: $nprogress-color;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,5 @@
|
||||||
|
# Auxiliary config
|
||||||
APP_CONFIG = YAML.load_file(Rails.root.join('config', 'justask.yml'))
|
APP_CONFIG = YAML.load_file(Rails.root.join('config', 'justask.yml'))
|
||||||
|
|
||||||
|
# Update rails config for mail
|
||||||
Rails.application.config.action_mailer.default_url_options = { host: APP_CONFIG['hostname'] }
|
Rails.application.config.action_mailer.default_url_options = { host: APP_CONFIG['hostname'] }
|
||||||
|
|
6
config/initializers/13_theme.rb
Normal file
6
config/initializers/13_theme.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Cache theme CSS if in production
|
||||||
|
$__THEME_CSS_CACHE_V1 = if Rails.env == 'production'
|
||||||
|
File.read Rails.root.join 'app/views/user/theme.css.scss.erb'
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end.freeze
|
|
@ -54,6 +54,10 @@ Rails.application.routes.draw do
|
||||||
match '/settings/profile', to: 'user#edit', via: 'get', as: :edit_user_profile
|
match '/settings/profile', to: 'user#edit', via: 'get', as: :edit_user_profile
|
||||||
match '/settings/profile', to: 'user#update', via: 'patch', as: :update_user_profile
|
match '/settings/profile', to: 'user#update', via: 'patch', as: :update_user_profile
|
||||||
|
|
||||||
|
match '/settings/theme', to: 'user#edit_theme', via: 'get', as: :edit_user_theme
|
||||||
|
match '/settings/theme', to: 'user#update_theme', via: 'patch', as: :update_user_theme
|
||||||
|
match '/settings/theme/preview.css', to: 'user#preview_theme', via: 'post', as: :preview_user_theme
|
||||||
|
|
||||||
# resources :services, only: [:index, :destroy]
|
# resources :services, only: [:index, :destroy]
|
||||||
match '/settings/services', to: 'services#index', via: 'get', as: :services
|
match '/settings/services', to: 'services#index', via: 'get', as: :services
|
||||||
match '/settings/services/:id', to: 'services#destroy', via: 'delete', as: :service
|
match '/settings/services/:id', to: 'services#destroy', via: 'delete', as: :service
|
||||||
|
|
6
db/20150724154106_create_themes_table.rb
Normal file
6
db/20150724154106_create_themes_table.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class CreateThemesTable < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :themes do |t|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
40
db/migrate/20150825073030_create_themes.rb
Normal file
40
db/migrate/20150825073030_create_themes.rb
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
class CreateThemes < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :themes do |t|
|
||||||
|
t.integer :user_id, null: false
|
||||||
|
|
||||||
|
t.integer :primary_color, limit: 4, default: 0x5E35B1
|
||||||
|
t.integer :primary_text, limit: 4, default: 0xFFFFFF
|
||||||
|
|
||||||
|
t.integer :danger_color, limit: 4, default: 0xFF0039
|
||||||
|
t.integer :danger_text, limit: 4, default: 0xFFFFFF
|
||||||
|
|
||||||
|
t.integer :success_color, limit: 4, default: 0x3FB618
|
||||||
|
t.integer :success_text, limit: 4, default: 0xFFFFFF
|
||||||
|
|
||||||
|
t.integer :warning_color, limit: 4, default: 0xFF7518
|
||||||
|
t.integer :warning_text, limit: 4, default: 0xFFFFFF
|
||||||
|
|
||||||
|
t.integer :info_color, limit: 4, default: 0x9954BB
|
||||||
|
t.integer :info_text, limit: 4, default: 0xFFFFFF
|
||||||
|
|
||||||
|
t.integer :default_color, limit: 4, default: 0x222222
|
||||||
|
t.integer :default_text, limit: 4, default: 0xEEEEEE
|
||||||
|
|
||||||
|
t.integer :panel_color, limit: 4, default: 0xF9F9F9
|
||||||
|
t.integer :panel_text, limit: 4, default: 0x151515
|
||||||
|
|
||||||
|
t.integer :link_color, limit: 4, default: 0x5E35B1
|
||||||
|
|
||||||
|
t.integer :background_color, limit: 4, default: 0xFFFFFF
|
||||||
|
t.integer :background_text, limit: 4, default: 0x222222
|
||||||
|
t.integer :background_muted, limit: 4, default: 0xBBBBBB
|
||||||
|
|
||||||
|
t.attachment :css
|
||||||
|
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :themes, [:user_id, :created_at]
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddShowForeignThemesToUsers < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :users, :show_foreign_themes, :boolean, default: true, null: false
|
||||||
|
end
|
||||||
|
end
|
101
db/schema.rb
101
db/schema.rb
|
@ -19,12 +19,11 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
create_table "answers", force: :cascade do |t|
|
create_table "answers", force: :cascade do |t|
|
||||||
t.text "content"
|
t.text "content"
|
||||||
t.integer "question_id"
|
t.integer "question_id"
|
||||||
t.integer "comment_count", default: 0, null: false
|
t.integer "comment_count", default: 0, null: false
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.integer "smile_count", default: 0, null: false
|
t.integer "smile_count", default: 0, null: false
|
||||||
t.boolean "nsfw", default: false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "answers", ["user_id", "created_at"], name: "index_answers_on_user_id_and_created_at", using: :btree
|
add_index "answers", ["user_id", "created_at"], name: "index_answers_on_user_id_and_created_at", using: :btree
|
||||||
|
@ -114,60 +113,6 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "oauth_access_grants", force: :cascade do |t|
|
|
||||||
t.integer "resource_owner_id", null: false
|
|
||||||
t.integer "application_id", null: false
|
|
||||||
t.string "token", null: false
|
|
||||||
t.integer "expires_in", null: false
|
|
||||||
t.text "redirect_uri", null: false
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.datetime "revoked_at"
|
|
||||||
t.string "scopes"
|
|
||||||
end
|
|
||||||
|
|
||||||
add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree
|
|
||||||
|
|
||||||
create_table "oauth_access_tokens", force: :cascade do |t|
|
|
||||||
t.integer "resource_owner_id"
|
|
||||||
t.integer "application_id"
|
|
||||||
t.string "token", null: false
|
|
||||||
t.string "refresh_token"
|
|
||||||
t.integer "expires_in"
|
|
||||||
t.datetime "revoked_at"
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.string "scopes"
|
|
||||||
end
|
|
||||||
|
|
||||||
add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree
|
|
||||||
add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree
|
|
||||||
add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree
|
|
||||||
|
|
||||||
create_table "oauth_applications", force: :cascade do |t|
|
|
||||||
t.string "name", null: false
|
|
||||||
t.string "uid", null: false
|
|
||||||
t.string "secret", null: false
|
|
||||||
t.text "redirect_uri", null: false
|
|
||||||
t.string "scopes", default: "", null: false
|
|
||||||
t.datetime "created_at"
|
|
||||||
t.datetime "updated_at"
|
|
||||||
t.integer "owner_id"
|
|
||||||
t.string "owner_type"
|
|
||||||
t.string "description"
|
|
||||||
t.string "icon_file_name"
|
|
||||||
t.string "icon_content_type"
|
|
||||||
t.integer "icon_file_size"
|
|
||||||
t.datetime "icon_updated_at"
|
|
||||||
t.integer "crop_x"
|
|
||||||
t.integer "crop_y"
|
|
||||||
t.integer "crop_w"
|
|
||||||
t.integer "crop_h"
|
|
||||||
t.boolean "icon_processing"
|
|
||||||
end
|
|
||||||
|
|
||||||
add_index "oauth_applications", ["name"], name: "index_oauth_applications_on_name", unique: true, using: :btree
|
|
||||||
add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree
|
|
||||||
add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree
|
|
||||||
|
|
||||||
create_table "questions", force: :cascade do |t|
|
create_table "questions", force: :cascade do |t|
|
||||||
t.string "content"
|
t.string "content"
|
||||||
t.boolean "author_is_anonymous"
|
t.boolean "author_is_anonymous"
|
||||||
|
@ -176,8 +121,7 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.integer "answer_count", default: 0, null: false
|
t.integer "answer_count", default: 0, null: false
|
||||||
t.boolean "nsfw", default: false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "questions", ["user_id", "created_at"], name: "index_questions_on_user_id_and_created_at", using: :btree
|
add_index "questions", ["user_id", "created_at"], name: "index_questions_on_user_id_and_created_at", using: :btree
|
||||||
|
@ -234,12 +178,12 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "users", force: :cascade do |t|
|
create_table "users", force: :cascade do |t|
|
||||||
t.string "email", default: "", null: false
|
t.string "email", default: "", null: false
|
||||||
t.string "encrypted_password", default: "", null: false
|
t.string "encrypted_password", default: "", null: false
|
||||||
t.string "reset_password_token"
|
t.string "reset_password_token"
|
||||||
t.datetime "reset_password_sent_at"
|
t.datetime "reset_password_sent_at"
|
||||||
t.datetime "remember_created_at"
|
t.datetime "remember_created_at"
|
||||||
t.integer "sign_in_count", default: 0, null: false
|
t.integer "sign_in_count", default: 0, null: false
|
||||||
t.datetime "current_sign_in_at"
|
t.datetime "current_sign_in_at"
|
||||||
t.datetime "last_sign_in_at"
|
t.datetime "last_sign_in_at"
|
||||||
t.string "current_sign_in_ip"
|
t.string "current_sign_in_ip"
|
||||||
|
@ -247,19 +191,19 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "screen_name"
|
t.string "screen_name"
|
||||||
t.integer "friend_count", default: 0, null: false
|
t.integer "friend_count", default: 0, null: false
|
||||||
t.integer "follower_count", default: 0, null: false
|
t.integer "follower_count", default: 0, null: false
|
||||||
t.integer "asked_count", default: 0, null: false
|
t.integer "asked_count", default: 0, null: false
|
||||||
t.integer "answered_count", default: 0, null: false
|
t.integer "answered_count", default: 0, null: false
|
||||||
t.integer "commented_count", default: 0, null: false
|
t.integer "commented_count", default: 0, null: false
|
||||||
t.string "display_name"
|
t.string "display_name"
|
||||||
t.integer "smiled_count", default: 0, null: false
|
t.integer "smiled_count", default: 0, null: false
|
||||||
t.boolean "admin", default: false, null: false
|
t.boolean "admin", default: false, null: false
|
||||||
t.string "motivation_header", default: "", null: false
|
t.string "motivation_header", default: "", null: false
|
||||||
t.string "website", default: "", null: false
|
t.string "website", default: "", null: false
|
||||||
t.string "location", default: "", null: false
|
t.string "location", default: "", null: false
|
||||||
t.text "bio", default: "", null: false
|
t.text "bio", default: "", null: false
|
||||||
t.boolean "moderator", default: false, null: false
|
t.boolean "moderator", default: false, null: false
|
||||||
t.string "profile_picture_file_name"
|
t.string "profile_picture_file_name"
|
||||||
t.string "profile_picture_content_type"
|
t.string "profile_picture_content_type"
|
||||||
t.integer "profile_picture_file_size"
|
t.integer "profile_picture_file_size"
|
||||||
|
@ -276,13 +220,10 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
t.boolean "privacy_show_in_search", default: true
|
t.boolean "privacy_show_in_search", default: true
|
||||||
t.boolean "permanently_banned", default: false
|
t.boolean "permanently_banned", default: false
|
||||||
t.boolean "blogger", default: false
|
t.boolean "blogger", default: false
|
||||||
t.boolean "nsfw", default: false
|
|
||||||
t.boolean "show_nsfw", default: false
|
|
||||||
t.boolean "privacy_allow_nsfw_questions", default: true
|
|
||||||
t.boolean "contributor", default: false
|
t.boolean "contributor", default: false
|
||||||
t.string "ban_reason"
|
t.string "ban_reason"
|
||||||
t.datetime "banned_until"
|
t.datetime "banned_until"
|
||||||
t.integer "comment_smiled_count", default: 0, null: false
|
t.integer "comment_smiled_count", default: 0, null: false
|
||||||
t.string "profile_header_file_name"
|
t.string "profile_header_file_name"
|
||||||
t.string "profile_header_content_type"
|
t.string "profile_header_content_type"
|
||||||
t.integer "profile_header_file_size"
|
t.integer "profile_header_file_size"
|
||||||
|
@ -292,10 +233,8 @@ ActiveRecord::Schema.define(version: 20150721154255) do
|
||||||
t.integer "crop_h_y"
|
t.integer "crop_h_y"
|
||||||
t.integer "crop_h_w"
|
t.integer "crop_h_w"
|
||||||
t.integer "crop_h_h"
|
t.integer "crop_h_h"
|
||||||
t.string "socket_key", default: ""
|
|
||||||
t.datetime "socket_key_expiry", default: '0001-01-01 00:00:00'
|
|
||||||
t.string "locale", default: "en"
|
t.string "locale", default: "en"
|
||||||
t.boolean "translator"
|
t.boolean "translator", default: false
|
||||||
t.string "confirmation_token"
|
t.string "confirmation_token"
|
||||||
t.datetime "confirmed_at"
|
t.datetime "confirmed_at"
|
||||||
t.datetime "confirmation_sent_at"
|
t.datetime "confirmation_sent_at"
|
||||||
|
|
Loading…
Reference in a new issue