Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//= require jquery.ui.autocomplete
//= require highcharts
//= require chartkick
//= require ./vendor/debounce
//= require_directory .
//= require_directory ./channels
//= require ./vendor/simplemde.min.js
124 changes: 124 additions & 0 deletions app/assets/javascripts/theming-editor/theming-editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//= require ../vendor/pickr.min.js

(function() {
function _onTextChange() {
var $input = $(this);
var variable = $input.attr('name');
var value = $input.val();

document.documentElement.style.setProperty(variable, value);
window.pickrs[variable].setColor(value, true);
}

function _onPickrChange(color, instance) {
var value = color ? '#' + color.toHEXA().join('') : '';
var $variable = $(instance.getRoot().root).parents('.theming-editor__variable');
$input = $variable.find('.theming-editor__input');
var variable = $input.attr('name');

// Don't update input if the user is typing in it
if (!$input.is(':focus')) {
$input.val(value);
}
// Update the picker button color (doesn't by default)
instance.applyColor(true);
// Update CSS property
document.documentElement.style.setProperty(variable, value);
}

function onSave() {
var $editor = $(this).parents('.theming-editor__wrapper');
var css = ':root {\n';
$editor.find('.theming-editor__input').each(function() {
var variable = $(this).attr('name');
var value = $(this).val();
css += ' ' + variable + ': ' + value + ';\n';
});
css += '}';
saveConfig(css);
}

function saveConfig(css) {
var data = {
hackathon_config: {
custom_css: css,
},
};
fetch('/manage/configs/custom_css', {
method: 'PATCH',
redirect: 'manual',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': Rails.csrfToken(),
},
body: JSON.stringify(data),
})
.then(function(response) {
if (!response.ok && response.type != 'opaqueredirect') {
alert('There was an error attempting to save. Please try again or refresh the page.');
return;
}
window.location.replace('/manage/configs/exit_theming_editor');
})
.catch(function() {
alert('There was an error attempting to save. Please try again or refresh the page.');
});
}

var onTextChange = throttle(_onTextChange, 100);
var onPickrChange = throttle(_onPickrChange, 100);

function initHtml() {
var variables = Object.values(getComputedStyle(document.documentElement))
.filter(function(x) {
return x.startsWith('--primary');
})
.sort();
var $editor = $('#theming-editor');
var $variables = $editor.find('.theming-editor__variables');
var $variable_template = $editor.find('.theming-editor__variable').remove();
variables.forEach(function(variable) {
var $new_variable = $variable_template.clone();
var $code = $new_variable.find('.theming-editor__variable-name-code');
var $input = $new_variable.find('.theming-editor__input');
var value = getComputedStyle(document.documentElement)
.getPropertyValue(variable)
.trim();

$code.text(variable);
$input.val(value);
$input.attr('name', variable);
$input.on('input', onTextChange);
$variables.append($new_variable);
});
$editor.find('.theming-editor__button-save').on('click', onSave);
}

function initColorPickers() {
window.pickrs = {};
$('.theming-editor__color-picker').each(function() {
var $input = $(this)
.parents('.theming-editor__variable')
.find('.theming-editor__input');
var pickr = Pickr.create({
el: this,
default: $input.val(),
components: {
opacity: false,
hue: true,
interaction: false,
},
});
pickr.on('change', onPickrChange);
var variable = $input.attr('name');
window.pickrs[variable] = pickr;
});
}

function init() {
initHtml();
initColorPickers();
}

document.addEventListener('turbolinks:load', init);
})();
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,21 @@ function debounce(func, wait, immediate) {
if (callNow) func.apply(context, args);
};
}

// Returns a function, that, as long as it continues to be invoked, will only
// trigger every N milliseconds. If `immediate` is passed, trigger the
// function on the leading edge, instead of the trailing.
function throttle(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
3 changes: 3 additions & 0 deletions app/assets/javascripts/vendor/pickr.min.js

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion app/assets/stylesheets/application.sass
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@
@import general/flashes
@import general/main
@import general/header
@import general/table
@import general/status-colors
@import general/table
@import forms/forms
@import forms/confirmation

@import general/theming-editor

// media queries needs to be last
@import general/media-queries

// external dependencies
@import font-awesome
@import vendor/pickr.min
59 changes: 59 additions & 0 deletions app/assets/stylesheets/general/_theming-editor.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.theming-editor__wrapper
position: fixed
bottom: 10px
right: 10px
display: block
background: #fff
border: 3px solid #ccc
padding: 15px 20px
border-radius: 4px
max-width: 470px
max-height: 700px
overflow: auto

.theming-editor__title
font-weight: bold
margin-bottom: 1em
font-size: 16px

.theming-editor__variables
display: flex
flex-flow: row wrap
margin: -10px -10px 10px

.theming-editor__variable
display: flex
flex-flow: column nowrap
margin: 10px
width: 200px

.theming-editor__variable-name
color: #e83e8c
margin-bottom: 5px
font-size: 11px

.theming-editor__input-group
display: flex
flex-flow: row nowrap
align-items: stretch

.theming-editor__input-group .pickr
margin-left: 5px
display: flex
width: 80px
button
box-shadow: 0 3px 4px rgba(0,0,0,0.1)
display: flex
height: 100%
width: 100%

input, textarea
&.theming-editor__input, &.theming-editor__input:focus
font-size: 12px
font-family: monospace
padding: 6px 9px
border: 1px solid #ccc
margin: 0

.theming-editor__button-wrapper
margin-top: 1em
3 changes: 3 additions & 0 deletions app/assets/stylesheets/vendor/pickr.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 32 additions & 3 deletions app/controllers/manage/configs_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Manage::ConfigsController < Manage::ApplicationController
before_action :limit_access_admin
before_action :get_config, only: [:edit, :update]
before_action :get_config, only: [:edit, :update, :update_only_css_variables]

respond_to :html, :json

Expand All @@ -15,8 +15,8 @@ def edit
def update
key = @config.var.to_sym
value = params[:hackathon_config][key]
value = true if value == 'true'
value = false if value == 'false'
value = true if value == "true"
value = false if value == "false"
if @config.value != value
@config.value = value
@config.save
Expand All @@ -26,6 +26,35 @@ def update
end
end

def update_only_css_variables
key = @config.var.to_sym
old_value = @config.value.strip
posted_value = params[:hackathon_config][key].strip
if old_value.include? ':root {'
# Replace the old CSS variables and keep the extra css
start_index = old_value.index(':root {')
end_index = old_value.index('}', start_index) + 1
pre_value = old_value[0...start_index].rstrip
post_value = old_value[end_index..-1].lstrip
new_value = "#{pre_value}\n\n#{posted_value}\n\n#{post_value}".strip
else
# Prepend the variable definitions to the existing value
new_value = "#{posted_value}\n\n#{old_value}"
end
params[:hackathon_config][key] = new_value
update
end

def enter_theming_editor
cookies[:theming_editor] = true
redirect_to root_path
end

def exit_theming_editor
cookies.delete :theming_editor
redirect_to manage_configs_path
end

private

def get_config
Expand Down
15 changes: 15 additions & 0 deletions app/views/layouts/_theming_editor.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.theming-editor__wrapper#theming-editor
.theming-editor__title Custom CSS Variables
.theming-editor__variables
.theming-editor__variable
%small.theming-editor__variable-name
%code.theming-editor__variable-name-code my-variable
.theming-editor__input-group
%input.theming-editor__input{type: 'text'}
.theming-editor__color-picker

.theming-editor__button-wrapper
%button.theming-editor__button-save{type: 'button'} Save
= link_to 'Cancel', exit_theming_editor_manage_configs_path

= javascript_include_tag "theming-editor/theming-editor.js", "data-turbolinks-eval": "false"
2 changes: 2 additions & 0 deletions app/views/layouts/application.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@
%section.section
.container
= yield
- if cookies[:theming_editor]
= render "layouts/theming_editor"
5 changes: 5 additions & 0 deletions app/views/manage/configs/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
%small
%code= key
%p.text-muted= t("simple_form.hints.hackathon_config.#{key}").html_safe
- if key == 'custom_css'
%p
= link_to enter_theming_editor_manage_configs_path do
%span.fa.fa-paint-brush.icon-space-r-half
Interactive editor
- if value == ''
%p.mb-0
%span.badge.badge-secondary Not set
Expand Down
2 changes: 1 addition & 1 deletion config/initializers/assets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.precompile += %w[manage.css vendor/*.js vendor/*.css]
Rails.application.config.assets.precompile += %w[manage.css vendor/*.js vendor/*.css theming-editor/*]
6 changes: 5 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@
post :mlh_info_applied, on: :collection
post :mlh_info_checked_in, on: :collection
end
resources :configs
resources :configs do
patch :update_only_css_variables, on: :member
get :enter_theming_editor, on: :collection
get :exit_theming_editor, on: :collection
end
resources :trackable_events
resources :trackable_tags
end
Expand Down
Loading