Commit 5546bed5 by Joren Mathews

First commit

parents
.recognitions {
margin-right: 20px;
}
.recognitions.loading:before {
content: 'loading...';
font-style: italic;
}
.recognition {
text-decoration: none;
background-color: #fff;
display: block;
padding: 10px;
color: #555;
margin-bottom: 5px;
}
.recognition p {
font-size: 14px;
}
.recognition button {
float: right;
opacity: 1;
z-index: 1;
position: relative;
cursor: pointer;
display: none;
}
.recognition h5 {
font-style: italic;
}
.recognition p, .recognition h5 {
margin: 0;
}
.recognition.archived * {
opacity: .6;
}
.recognition.archived button {
display: block;
}
\ No newline at end of file
<?php
function recognitions_admin_page() {
wp_enqueue_script('wp-api');
wp_enqueue_style('recognitions-admin', plugin_dir_url(__FILE__) . 'admin.css');
require 'template.php';
}
add_action('admin_menu', 'register_values_board_admin_page');
function register_values_board_admin_page() {
add_menu_page('recognitions', 'Values Board', 'administrator', 'recognitions-admin-page', 'recognitions_admin_page');
}
// Messages
if (!function_exists('acf_add_local_field_group')):
function acf_missing_error_notice() {
?>
<div class="error notice">
<p><?php _e('The Values Board plugin requires the <a target="_blank" href="https://wordpress.org/plugins/advanced-custom-fields/">ACF plugin</a> to function.', 'values_board'); ?></p>
</div>
<?php
}
add_action('admin_notices', 'acf_missing_error_notice');
endif;
$options = get_option('values_board_options');
if (!$options || !$options['values_board_field_values']):
function values_missing_error_notice() {
?>
<div class="error notice">
<p><?php _e('You need to populate some values for the <a href="/wp-admin/admin.php?page=values_board">Values Board plugin</a>.', 'values_board'); ?></p>
</div>
<?php
}
add_action('admin_notices', 'values_missing_error_notice');
endif;
$users = get_users(array(
'role' => 'author'
));
if (!$users || !count($users)):
function users_missing_error_notice() {
?>
<div class="error notice">
<p><?php _e('You need to populate some <a href="/wp-admin/users.php">users</a> with the Author role for the Values Board plugin.', 'values_board'); ?></p>
</div>
<?php
}
add_action('admin_notices', 'users_missing_error_notice');
endif;
?>
\ No newline at end of file
<?php
function values_board_settings_init() {
register_setting('values_board', 'values_board_options');
add_settings_section(
'values_board_section_developers',
null,
'values_board_section_developers_cb',
'values_board'
);
// register a new field in the "values_board_section_developers" section, inside the "values_board" page
add_settings_field(
'values_board_field_values', // as of WP 4.6 this value is used only internally
// use $args' label_for to populate the id inside the callback
__('Values', 'values_board'),
'values_board_field_values_cb',
'values_board',
'values_board_section_developers',
[
'label_for' => 'values_board_field_values',
'class' => 'values_board_row',
'values_board_custom_data' => 'custom',
]
);
add_settings_field(
'values_board_field_colors', // as of WP 4.6 this value is used only internally
// use $args' label_for to populate the id inside the callback
__('Colors', 'values_board'),
'values_board_field_colors_cb',
'values_board',
'values_board_section_developers',
[
'label_for' => 'values_board_field_colors',
'class' => 'values_board_row',
'values_board_custom_data' => 'custom',
]
);
}
add_action('admin_init', 'values_board_settings_init');
function values_board_section_developers_cb($args) {
// HTML
}
function values_board_field_values_cb($args) {
$options = get_option('values_board_options');
?>
<textarea rows="10" cols="30" id="<?php echo esc_attr($args['label_for']); ?>" name="values_board_options[<?php echo esc_attr($args['label_for']); ?>]"><?php echo $options[$args['label_for']]; ?></textarea>
<p class="description">
<?php esc_html_e('Enter a list of values. One per line.', 'values_board'); ?>
</p>
<?php
}
function values_board_field_colors_cb($args) {
$options = get_option('values_board_options');
?>
<textarea rows="10" cols="15" id="<?php echo esc_attr($args['label_for']); ?>" name="values_board_options[<?php echo esc_attr($args['label_for']); ?>]"><?php echo $options[$args['label_for']]; ?></textarea>
<p class="description">
<?php esc_html_e('Enter a list of colors that correspond to the values above. One per line.', 'values_board'); ?>
</p>
<?php
}
function values_board_options_page() {
// add top level menu page
add_submenu_page(
'recognitions-admin-page',
'Settings',
'Settings',
'manage_options',
'values_board',
'values_board_options_page_html'
);
}
add_action('admin_menu', 'values_board_options_page');
function values_board_options_page_html() {
// check user capabilities
if (!current_user_can('manage_options')) {
return;
}
// add error/update messages
// check if the user have submitted the settings
// wordpress will add the "settings-updated" $_GET parameter to the url
if (isset($_GET['settings-updated'])) {
// add settings saved message with the class of "updated"
add_settings_error('values_board_messages', 'values_board_message', __('Settings Saved', 'values_board'), 'updated');
}
// show error/update messages
settings_errors('values_board_messages');
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<form action="options.php" method="post">
<?php
// output security fields for the registered setting "values_board"
settings_fields('values_board');
// output setting sections and their fields
// (sections are registered for "values_board", each field is registered to a specific section)
do_settings_sections('values_board');
// output save settings button
submit_button('Save Settings');
?>
</form>
</div>
<?php
}
\ No newline at end of file
<div class="wrap">
<h1>Recognitions Admin</h1>
<br>
</div>
<div class="controls_header">
<select id="year_filter">
<?php
$years = array(Date('Y'), Date('Y')-1);
foreach ($years as $i => $year) {
echo '<option value="' . $year . '">' . $year . '</option>';
} ?>
</select>
<select id="month_filter">
<?php
$months = array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
foreach ($months as $i => $month) {
echo '<option ' . (Date('F') == $month ? 'selected="selected"' : '') . ' value="' . $month . '">' . $month . '</option>';
} ?>
</select>
<button id="archive_month">Archive Month</button>
</div>
<br>
<div class="recognitions">
</div>
<script>
jQuery(($) => {
var recognitionsWrapper = $('.recognitions');
var loadedRecognitions = null;
var currentMonth = null;
var currentYear = <?php echo Date('Y'); ?>;
var loadRecognitions = (year, month) => {
recognitionsWrapper.addClass('loading');
$.get('/values-board/archives?month=' + month + '&year=' + year, (response) => {
loadedRecognitions = $.parseJSON(response);
populateRecognitions(loadedRecognitions);
recognitionsWrapper.removeClass('loading');
});
}
// Debug
// var posts = new wp.api.collections.Posts();
// posts.fetch({data: {per_page: 100, status: 'any', filter: {'orderby': 'title', 'order': 'DESC'}}}).done(() => {
// console.log(posts);
// var loadedPosts = _.map(posts.models, post => post.attributes);
// });
var populateRecognitions = loadedRecognitions => {
recognitionsWrapper.html('');
loadedRecognitions.map(recognition => {
var recognitionElement = $('<a class="recognition"></a>');
recognitionElement.addClass(recognition.post_status == 'draft' ? 'archived' : '');
recognitionElement.attr('href', `/wp-admin/post.php?post=${recognition.ID}&action=edit`);
recognitionElement.attr('data-recognition-id', recognition.ID);
var note = recognition.acf.note;
var values = `<h5>${recognition.acf.value.split(',').join(', ')}</h5>`
var publishButton = '<button class="publish">Publish</button>';
recognitionElement.append(publishButton);
recognitionElement.append(note);
recognitionElement.append(values);
recognitionElement.appendTo(recognitionsWrapper);
});
}
var publishRecognition = (id) => {
$.post('/values-board/toggle-status?status=publish&id=' + id, (response) => {
$(`.recognition[data-recognition-id=${id}]`).removeClass('archived');
});
}
var archiveMonth = () => {
loadedRecognitions.map(loadedRecognition => {
$.post('/values-board/toggle-status?status=draft&id=' + loadedRecognition.ID, (response) => {
$(`.recognition[data-recognition-id=${loadedRecognition.ID}]`).addClass('archived');
});
});
}
$('.recognitions').on('click', 'button', (e) => {
var clicked = $(e.target);
var id = clicked.parent().attr('data-recognition-id');
publishRecognition(id);
return false;
});
$('#year_filter').change(e => {
currentYear = $(e.target).val();
loadRecognitions(currentYear, currentMonth);
});
$('#month_filter').change(e => {
currentMonth = $(e.target).val();
loadRecognitions(currentYear, currentMonth);
}).trigger('change');
$('#archive_month').click(e => {
archiveMonth();
});
})
</script>
\ No newline at end of file
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
\ No newline at end of file
node_modules/
\ No newline at end of file
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: path.join(__dirname, 'app'),
entry: path.join(__dirname, 'app', 'entry.jsx'),
output: {
path: path.resolve(__dirname, "bin"),
filename: 'app.bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
plugins: [
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
$: "jquery",
jQuery: "jquery"
})
],
watch: true
};
@import './vars.styl'
@import './imports/*'
@import './components/*'
#values_board
padding: 2rem 0
fixed: top 0 left 0
width: 100%
height: 100%
overflow: auto
font-family: 'Open Sans'
z-index: 40
bgimage('halftone.png', false)
*
font-family: 'Open Sans'
box-sizing: border-box
\ No newline at end of file
button.add
border-radius: 100%
background-color: $yellow
border: none
width: 2.2rem
height: 2.2rem
padding: 0
margin: 7px 0 0 0
position: relative
outline: none
cursor: pointer
&:after
content: '+'
centered()
font-size: 39px
font-weight: 300
color: black
top: 45%
#add
display: none
background-color: white
padding: 1rem 1rem .5rem 1rem
box-shadow: 3px 4px 5px 0px rgba(0,0,0,0.1)
width: 300px
margin: 1rem auto
img
width: 4rem
&.show
display: block
label
font-weight: bold
display: block
margin: .5rem 0 0 0
input[type="text"]
padding: 5px
font-size: 20px
border: 2px solid #eee
width: calc(100% - .8rem)
select
width: 100%
height: 7rem
input[type="submit"]
background-color: $yellow
color: black
padding: .5rem
margin: 1rem 0 .5rem 0
border: none
cursor: pointer
font-weight: bold
section.app
margin-top: 2rem
h1
font-size: 38px
font-weight: 300
margin: 3rem 0 0 2rem
img
width: 300px
height: auto
margin-right: 10px
\ No newline at end of file
.recognitions
padding: 50px 15px 15px 15px
overflow: hidden
display: flex
flex-wrap: wrap
justify-content: left
.recognition
background-color: white
padding: 5px 10px 10px 10px
margin-right: 15px
margin-top: 15px
flex: 0 0 240px
h2
margin: 0
font-size: 18px
.note
margin: 5px 0
p
margin: 0
font-size: 17px
.value
background-color: $yellow
color: white
padding: 4px 8px
margin-top: 5px
margin-right: 5px
border-radius: 3px
display: inline-block
text-transform: uppercase
font-size: 14px
font-weight: bold
&.color_0
background-color: #4f514f
&.color_1
background-color: #ce9d69
&.color_2
background-color: #1d7aa2
&.color_3
background-color: #6cc1b3
&.color_4
background-color: #f45e58
\ No newline at end of file
.user_wrapper
position: relative
min-height: 100px
margin: 20px 15px
box-shadow: 3px 4px 5px 0px rgba(0,0,0,0.1)
&:nth-child(odd)
background-color: rgba(20,20,20, .7)
&:nth-child(even)
background-color: rgba(20,20,20, .8)
.user
absolute: top 0 left 0
width: 100%
background-color: black
h2
color: white
font-size: 20px
padding: 5px 20px
white-space: nowrap
height: 40px
line-height: 40px
float: left
margin: 0
clear: none
img
width: 50px
height: 50px
float: left
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 293.26 45.78"><defs><style>.cls-1{fill:#000;}</style></defs><title>3FO_Logo_New</title><path class="cls-1" d="M22.78,20.39c3-1.64,6.53-4.59,6.53-9.47C29.31,5.58,24.85.19,14.88.19,10.19.19,4.61,2.14,2.43,3L2.31,3l2.4,5.63.11,0c6.08-2,11.18-2.16,14-.49a3.85,3.85,0,0,1,2,2.62,4.18,4.18,0,0,1-1.06,3.41c-1.92,2.33-5.89,3.74-10.61,3.78H9v6.21h.13c9.55.07,13,4,13,7.64a6.21,6.21,0,0,1-2.68,5.44C16.88,39,10,40.14,2.65,37.34l-.1,0L0,42.65l.12.05a32.71,32.71,0,0,0,13.34,3.06c11.09,0,18-7.11,18-13.71C31.41,26.53,28.51,22.61,22.78,20.39Z"/><path class="cls-1" d="M86.82,0A15.27,15.27,0,0,0,73.1,7.43c-2.5,4-3.88,9.47-3.88,15.49s1.38,11.47,3.9,15.42a15.29,15.29,0,0,0,13.7,7.36,15.6,15.6,0,0,0,13.77-7.39c2.56-4,4-9.48,4-15.46s-1.41-11.47-4-15.46A15.62,15.62,0,0,0,86.82,0Zm-.07,38.66c-6.11,0-9.08-5.15-9.08-15.74S80.64,7,86.75,7s9.36,5.32,9.36,15.81S93,38.66,86.75,38.66Z"/><path class="cls-1" d="M49.48,0A15.28,15.28,0,0,0,35.75,7.43c-2.5,4-3.87,9.47-3.87,15.49s1.38,11.47,3.9,15.42a15.29,15.29,0,0,0,13.7,7.36,15.63,15.63,0,0,0,13.77-7.39c2.56-4,4-9.48,4-15.46s-1.41-11.47-4-15.46A15.65,15.65,0,0,0,49.48,0Zm-.07,38.66c-6.11,0-9.08-5.15-9.08-15.74S43.3,7,49.41,7s9.36,5.32,9.36,15.81S55.62,38.66,49.41,38.66Z"/><path class="cls-1" d="M225.13,0A15.29,15.29,0,0,0,211.4,7.43c-2.5,4-3.87,9.47-3.87,15.49s1.38,11.47,3.9,15.42a15.29,15.29,0,0,0,13.7,7.36,15.6,15.6,0,0,0,13.77-7.39c2.56-4,4-9.48,4-15.46s-1.41-11.47-4-15.46A15.62,15.62,0,0,0,225.13,0Zm-.07,38.66c-6.11,0-9.08-5.15-9.08-15.74S219,7,225.06,7s9.36,5.32,9.36,15.81S231.27,38.66,225.06,38.66Z"/><polygon class="cls-1" points="199.3 9.55 199.3 10.44 199.3 10.44 199.3 9.55"/><path class="cls-1" d="M112.23,18.74s2.22-.07,2.22-4.41V8h17.91V1H106.67V45.43h7.78v-19h10.71v-7H112.23C111.54,19.34,111.83,18.74,112.23,18.74Z"/><path class="cls-1" d="M206.32,38.5l-.12,0c-3,.76-5,1-6,.29-.67-.52-.94-1.55-.94-3.57V19.17H205V13.45h-7.84c-.69,0-.4-.6,0-.6,0,0,2.09-.07,2.14-4.24V.76h-8V13.44h-2.1v5.73h2.1V35.53c0,4.61,1.59,10.1,9.15,10.1A19.63,19.63,0,0,0,207.71,44l.09,0Z"/><path class="cls-1" d="M291.78,38.5l-.12,0c-3,.76-5,1-6,.29-.66-.52-.94-1.55-.94-3.57V19.17h5.7V13.45h-7.84c-.69,0-.4-.6,0-.6,0,0,2.09-.07,2.14-4.24V.76h-8V13.44h-2.1v5.73h2.1V35.53c0,4.61,1.59,10.1,9.15,10.1A19.63,19.63,0,0,0,293.17,44l.09,0Z"/><path class="cls-1" d="M173.75,13.23c-5,0-9.13,1.67-11.87,4.82A16.82,16.82,0,0,0,158.1,29.3c0,10.42,5.78,16.4,15.86,16.4a28.28,28.28,0,0,0,12.5-3l.13-.07L185,36.79l-.11,0-.46.16c-1.71.62-7,2.37-10.51,2.37-5.71,0-6.89-4-7.26-7.93h20.65l0-.11c.89-6.26,0-11-2.65-14C182.39,14.6,178.7,13.23,173.75,13.23ZM167,25.57c.78-4,3.16-6,7.07-6,4.53,0,5.54,2.19,5.7,6Z"/><path class="cls-1" d="M142.09,13.23c-5,0-9.13,1.67-11.87,4.82a16.82,16.82,0,0,0-3.78,11.25c0,10.42,5.78,16.4,15.85,16.4a28.29,28.29,0,0,0,12.51-3l.13-.07-1.55-5.8-.12,0-.46.16c-1.71.62-7,2.37-10.51,2.37-5.7,0-6.88-4-7.25-7.93h20.65l0-.11c.89-6.26,0-11-2.66-14C150.73,14.6,147,13.23,142.09,13.23Zm-6.74,12.34c.79-4,3.17-6,7.08-6,4.53,0,5.54,2.19,5.7,6Z"/><path class="cls-1" d="M272.4,38.75c0-1.72,0-24,0-24h-8.24s0,17.41,0,18.5a5.15,5.15,0,0,1-1.29,4.07,7.45,7.45,0,0,1-5.58,2,3.83,3.83,0,0,1-3-1.35c-.86-1-.94-2.74-.9-4.34v-.07c0-.33,0-.67,0-1V14.7h-8.24V32.94c0,6,1.27,12.82,11.17,12.82A28,28,0,0,0,264,44.5c.1,0,.61-.22,1.44-.54l.32-.12a17.61,17.61,0,0,0,.75,1.85l0,.09,6.61-1.43,0-.13A30.54,30.54,0,0,1,272.4,38.75Z"/></svg>
\ No newline at end of file
// Mixins!
cover()
absolute: top 0 left 0
width: 100%
height: 100%
centered()
absolute: top 50% left 50%
transform: translate(-50%, -50%)
hcentered()
absolute: left 50%
transform: translateX(-50%)
vcentered()
absolute: top 50%
transform: translateY(-50%)
perheight(percent)
&:after
display: block
content: ' '
padding-top: percent
background($type)
if $type == 'cover'
background-size: cover
background-position: center center
background-repeat: no-repeat
if $type == 'contain'
background-size: contain
background-position: center center
background-repeat: no-repeat
bgimage($imageName, $absolute)
if $absolute
background-image: url('/wp-content/themes/threefo_values/css/images/' + $imageName)
else
background-image: url('images/' + $imageName)
darkoverlay()
&:before
content ''
position absolute
width 100%
height 100%
background-color rgba($black, 0.15)
\ No newline at end of file
$yellow = #e7ca27
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var gutil = require('gulp-util');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var plumber = require('gulp-plumber');
var cleanCSS = require('gulp-clean-css');
var stylus = require('gulp-stylus');
var axis = require('axis');
var jeet = require('jeet');
var rupture = require('rupture');
gulp.task('stylus', function() {
gulp.src('./css/app.styl')
.pipe(plumber())
.pipe(sourcemaps.init())
.pipe(stylus({use: [axis(), jeet(), rupture()], compress: true}))
.pipe(rename('site.min.css'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('./css/'));
});
gulp.task('watch', function() {
gulp.watch('./css/**/*.styl', ['stylus']);
});
gulp.task('default', ['stylus', 'watch']);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "SchedulingBoard",
"version": "0.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"flux": "^3.1.3",
"jquery": "^3.3.1",
"lodash": "^4.17.11",
"react": "^16.5.2",
"react-datepicker": "^1.6.0",
"react-dnd-html5-backend": "^5.0.1",
"react-dom": "^16.5.2",
"sifter": "^0.5.2"
},
"devDependencies": {
"@babel/core": "^7.1.0",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",
"axis": "^1.0.0",
"babel-loader": "^8.0.2",
"gulp": "^3.9.1",
"gulp-clean-css": "^3.10.0",
"gulp-concat": "^2.6.1",
"gulp-plumber": "^1.2.0",
"gulp-rename": "^1.4.0",
"gulp-sourcemaps": "^2.6.4",
"gulp-stylus": "^2.7.0",
"gulp-uglify": "^3.0.1",
"jeet": "^7.2.0",
"rupture": "^0.7.1",
"webpack": "^4.19.1",
"webpack-cli": "^3.1.0"
},
"scripts": {
"start": "webpack --mode development",
"build": "webpack --mode production"
},
"author": "",
"license": "ISC"
}
class Add extends React.Component {
constructor(props) {
super(props);
this.state = {show: false};
this.state.recognition = this.getEmptyRecognition();
}
getEmptyRecognition() {
return {
title: '',
note: '',
value: [],
who: ''
}
}
componentWillMount() {
this.addAction = this.addAction.bind(this);
emitter.on('add', this.addAction);
}
componentDidMount() {
}
componentWillUnmount() {
emitter.removeListener('add', this.addAction);
}
addAction(userData) {
this.state.recognition = this.getEmptyRecognition();
this.state.recognition.who = userData.ID;
this.toggle();
}
toggle() {
this.state.show = !this.state.show;
let newState = deepCopy(this.state);
this.setState(newState);
if (this.state.show) {
setTimeout(function() {
$('input[name="note"]').focus();
});
} else {
$('input[name="note"]').val('');
}
}
setValue(field, e) {
let newState = _.clone(this.state);
let value = e.target.value;
if (field == 'value') {
if (_.includes(newState.recognition.value, value)) {
newState.recognition.value = _.filter(newState.recognition.value, function(existingValue) {
return existingValue != value;
});
} else {
newState.recognition.value.push(value);
}
} else {
newState.recognition[field] = value;
}
this.setState(newState);
}
handleSubmit(e) {
e.preventDefault();
let recognitionData = {
title: this.state.recognition.note,
fields: {
note: this.state.recognition.note,
who: this.state.recognition.who,
value: this.state.recognition.value