Commit 31d63aa4 authored by colemanw's avatar colemanw

Upgrade shoreditch to 0.1-alpha24

parent 011016c5
......@@ -13,24 +13,40 @@
If you are doing development on this extension, then you may need to build
new CSS files. This requires the toolchain for SCSS=>CSS compilation.
First of all you need [NodeJS](https://nodejs.org/). Please be aware that currently Shoreditch *does not* support NodeJS v6 or higher! It is recommended that you install NodeJS **v5.12.0** (you can use [nvm](https://github.com/creationix/nvm) for managing multiple node versions on the same machine.
First of all you need [NodeJS](https://nodejs.org/). Please be aware that currently Shoreditch *does not* support NodeJS v9 or higher! It is recommended that you install NodeJS LTS version **v8.9.4** (you can use [nvm](https://github.com/creationix/nvm) for managing multiple node versions on the same machine.
Once you have NodeJS installed, run
```
npm install -g gulp
```sh
npm install
```
Once you have the tools, you can run `gulp`. This will monitor the SCSS files and automatically recompile whenever they change.
Once you have the tools, you can run `npx gulp watch`. This will monitor the SCSS files and automatically recompile whenever they are changed.
```sh
# npx command ensures you run a local repository Gulp and not the global one
npx gulp watch
```
gulp
If you would like to just compile files without watching, simply run `npx gulp`.
```sh
npx gulp
```
## Guidelines for `custom-civicrm.css`
Any style changes that are aimed at making the core screens look like they are part of the Bootstrap theme, should go here.
### Disable stylelint rules
Any .scss file under the `civicrm/` folder must have this annotation at the very top
```scss
/* stylelint-disable max-nesting-depth, selector-max-compound-selectors, selector-no-qualifying-type, selector-max-id */
```
in order to tell [stylelint](https://stylelint.io/) to be more a bit more lax when enforcing style conventions
*TBD*
## Guidelines for `bootstrap.css`
......
......@@ -23,7 +23,7 @@ If you'd like to contribute to the project, please make sure to familiarize with
* Reference any issues or pull requests that you think is useful to mention
### Submitting a PR
When your work is complete and you have tested it locally, you can open a PR against the `develop` branch.
When your work is complete and you have tested it locally, you can open a PR against the `master` branch.
In the PR give a description of what you changed (and why!), and attach before & after screenshots to show the effects of your changes.
......
# org.civicrm.shoreditch (developmental)
The "Shoreditch" extension is a theme for CiviCRM based on a contemporary [flat design](https://en.wikipedia.org/wiki/Flat_design) and
[Bootstrap(S)CSS](http://getbootstrap.com/css/). It includes two major components:
the [Bootstrap v3](https://getbootstrap.com/docs/3.3/) framework.
Please note that this extension is currrently in **alpha stage** and under **active development**. Significant elements may change.
## Supported CMSs
At the moment the theme is being developed to work only in Drupal (with default theme set to "Seven"). WordPress and Joomla are not currently supported.
## Components
The theme includes two major components:
* "`bootstrap.css`" is a build of Bootstrap based on the standard Bootstrap style-guide. It can be used with other CiviCRM extensions which satisfy the Bootstrap style-guide.
* "`custom-civicrm.css`" is an optional replacement for "civicrm.css". It uses the same visual conventions and SCSS metadata, but it applies to existing core screens.
> This extension is under **active development**. Significant elements may change.
### Using `bootstrap.css`
This extension provides the CSS for Bootstrap. Other extensions should output compliant HTML, e.g.
......
/**
* Resets css rules that are applied by the CiviCRM style
*
* (`initial` was used at first, but there is no support by IE for it)
* Resets css rules that are applied by the original CiviCRM style
* and the "legacy mode" of Shoreditch
*/
h3 {
@include initial(background-color, transparent);
@include initial(border, 0);
@include initial(border-radius, 0);
@include initial(box-shadow, none);
@include initial(font-family, $font-family-base);
@include initial(padding, 0);
@include initial(margin, 0);
font-size: $font-size-h3;
font-weight: 400;
font-size: $font-size-h3;
}
table {
......@@ -52,6 +54,12 @@ table {
}
.crm-button .crm-i {
left: .6em;
top: .6em;
left: 0.6em;
top: 0.6em;
}
label .crm-error-label {
@include initial(padding, 0);
font-size: $font-size-base;
}
var gulp = require('gulp');
var bulk = require('gulp-sass-bulk-import');
var bulk = require('gulp-sass-glob');
var sass = require('gulp-sass');
var postcss = require('gulp-postcss');
var postcssPrefix = require('postcss-prefix-selector');
......@@ -9,8 +9,11 @@ var transformSelectors = require('gulp-transform-selectors');
var civicrmScssRoot = require('civicrm-scssroot')();
var bootstrapNamespace = '#bootstrap-theme';
var outsideNamespaceRegExp = /^\.___outside-namespace/;
gulp.task('sass:bootstrap', ['sass:sync'], function () {
gulp.task('sass:sync', civicrmScssRoot.update);
gulp.task('sass:bootstrap', gulp.series('sass:sync', function buildBootstrapCSS () {
return gulp.src('scss/bootstrap/bootstrap.scss')
.pipe(bulk())
.pipe(sass({
......@@ -21,13 +24,14 @@ gulp.task('sass:bootstrap', ['sass:sync'], function () {
.pipe(stripCssComments({ preserve: false }))
.pipe(postcss([postcssPrefix({
prefix: bootstrapNamespace + ' ',
exclude: [/^html/, /^body/, /\.ta-hidden-input/, /\.mobile/]
exclude: [/^html/, /^body/, /\.ta-hidden-input/, outsideNamespaceRegExp]
})]))
.pipe(transformSelectors(namespaceRootElements, { splitOnCommas: true }))
.pipe(transformSelectors(removeOutsideNamespaceMarker, { splitOnCommas: true }))
.pipe(gulp.dest('css/'));
});
}));
gulp.task('sass:civicrm', ['sass:sync'], function () {
gulp.task('sass:civicrm', gulp.series('sass:sync', function buildCiviCRMCSS () {
return gulp.src('scss/civicrm/custom-civicrm.scss')
.pipe(bulk())
.pipe(sass({
......@@ -39,22 +43,20 @@ gulp.task('sass:civicrm', ['sass:sync'], function () {
.pipe(postcss([postcssPrefix({
prefix: '.crm-container ',
exclude: [/^body/, /tooltip/, /page-civicrm/, /crm-container/,
/civicrm-menu/, /#root-menu-div/]
/ui-datepicker/, /civicrm-menu/, /#root-menu-div/, /jstree-contextmenu/,
outsideNamespaceRegExp]
}), postcssDiscardDuplicates]))
.pipe(transformSelectors(removeOutsideNamespaceMarker, { splitOnCommas: true }))
.pipe(gulp.dest('css/'));
});
gulp.task('sass:sync', function () {
civicrmScssRoot.updateSync();
});
}));
gulp.task('sass', ['sass:bootstrap', 'sass:civicrm']);
gulp.task('sass', gulp.parallel('sass:bootstrap', 'sass:civicrm'));
gulp.task('watch', function () {
gulp.watch(civicrmScssRoot.getWatchList(), ['sass']);
gulp.watch(civicrmScssRoot.getWatchList(), gulp.parallel('sass'));
});
gulp.task('default', ['sass']);
gulp.task('default', gulp.parallel('sass'));
/**
* Apply the namespace on html and body elements
......@@ -73,3 +75,14 @@ function namespaceRootElements (selector) {
return selector;
}
/**
* Deletes the special class that was used as marker for styles that should
* not be nested inside the bootstrap namespace from the given selector
*
* @param {String} selector
* @return {String}
*/
function removeOutsideNamespaceMarker (selector) {
return selector.replace(outsideNamespaceRegExp, '');
}
......@@ -14,8 +14,8 @@
<url desc="Support">http://civicrm.stackexchange.com/</url>
<url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
</urls>
<releaseDate>2017-11-27</releaseDate>
<version>0.1-alpha14</version>
<releaseDate>2018-08-20</releaseDate>
<version>0.1-alpha24</version>
<compatibility>
<ver>4.7</ver>
</compatibility>
......
(function ($) {
$(document).ready(function () {
moveUserPictureNextToContactTitle();
});
/**
* Moves the user image to the left of the contact name
*/
function moveUserPictureNextToContactTitle () {
$('.crm-summary-contactname-block').prepend($('#crm-contact-thumbnail'));
}
}(CRM.$));
......@@ -4,6 +4,19 @@
(function ($, _) {
// [ML] removed menu hack
/**
* Substitutes main menu arrow image with FontAwesome caret icon
*/
function substituteMenuArrows() {
$('#root-menu-div .menu-item-arrow').each(function ($element) {
var $arrow = $(this);
$arrow.before('<i class="fa fa-caret-right menu-item-arrow"></i>');
$arrow.remove();
});
}
$(document).ready(function () {
substituteMenuArrows();
});
}(CRM.$, CRM._));
/* globals MutationObserver, CRM */
CRM.$(function () {
'use strict';
/**
* The purpose of this script is to activate the "select2" dropdowns on standard select elements.
* When the "select2" is enabled, its corresponding select is hidden, so we're
* only targeting the visible ones.
* Because some select elements are dinamically loaded via AJAX,
* we're using the "MutationObserver" to listen to DOM changes
*/
/**
* We're debouncing the callback to avoid calling the plugin multiple times
* during DOM changes
*/
var observer = new MutationObserver(debounce(function () {
CRM.$('select:visible:not(.no-select2):not(.crm-form-multiselect)')
.each(function () {
var select = CRM.$(this);
var hasNoSelect2Parent = select.closest('.no-select2').length;
/**
* The parent selector does not work on the previous query. This query
* `:not(.no-select2) select`
* will still transform the select inputs into select2 components.
* By adding the condition inside a .each we fix this issue.
*/
if (hasNoSelect2Parent) {
return;
}
select.select2({ containerCss: { display: 'inline-block' } })
.on('change', clearSelect2);
});
}, 50));
observer.observe(document.querySelector('body'), {
childList: true,
subtree: true
});
function debounce (fn, delay) {
var timer = null;
return function () {
var me = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(me, args);
}, delay);
};
}
/**
* Walk through all select fields and hide it
* if there isn't any option
*/
function clearSelect2 () {
window.setTimeout(function () {
CRM.$('select').each(function (idx, item) {
var id = '#s2id_' + CRM.$(item).attr('id');
var optionsLength = CRM.$(item).find('option').length;
if (optionsLength === 0) {
CRM.$(id).remove();
}
});
}, 50);
}
});
(function ($, _) {
(function ($, _, ts) {
$(document).ready(function () {
amendMarkupOfMenuItemsWithFontAwesomeIcons();
customizeQuickSearchField();
......@@ -20,7 +20,7 @@
* Changes the placeholder text of the quicksearch field
*/
function changeQuickSearchFieldPlaceholder () {
$('#crm-qsearch .ui-autocomplete-input').attr('placeholder', 'Quick Search');
$('#crm-qsearch .ui-autocomplete-input').attr('placeholder', ts('Quick Search'));
}
/**
......@@ -63,7 +63,9 @@
* @return {boolean}
*/
function isQuickSearchOnGoing () {
return !!$('#sort_name_navigation').val().trim();
var searchValue = $('#sort_name_navigation').val() || '';
return !!searchValue.trim();
}
/**
......@@ -127,13 +129,16 @@
}
/**
* Creates an HTML element out of the text node of the given menu item
* Creates an HTML element out of the text node next to the icon (an element
* with either the .crm-i or the .fa class) of the given menu item
*
* @param {object} $menuItem
*/
function wrapMenuItemLabelInHTML ($menuItem) {
$menuItem.contents().filter(function () {
return this.nodeType === 3 && $(this).parent().is($menuItem);
}).wrap('<span class="menumain-label" />')
var itemLabel = $('.crm-i, .fa', $menuItem)[0].nextSibling;
if (itemLabel.nodeType === Node.TEXT_NODE) {
$(itemLabel).wrap('<span class="menumain-label" />');
}
}
}(CRM.$, CRM._));
}(CRM.$, CRM._, CRM.ts('org.civicrm.shoreditch')));
CRM.$(function() {
'use strict';
/**
* We're debouncing the callback to avoid calling multiple times during DOM changes
*/
var observer = new MutationObserver(debounce(function() {
/**
* The customized radio buttons / checkboxes depend on the existence of the
* "for" attribute in the respective labels.
* This is a workaround to add any missing "for" attributes to the markup.
* @see: org.civicrm.shoreditch/scss/civicrm/common/_radio-checkbox.scss
*/
CRM.$('.crm-container input[type=checkbox], .crm-container input[type=radio]').each(function() {
var $this = CRM.$(this);
var label = $this.next('label');
if (!$this.attr('id')) {
// There's no id. Add a unique random value as the id
$this.attr('id', new Date().valueOf());
}
if (!label.length) {
// There's no sibling label. Let's just show the checkbox / radio button, in order to avoid feature loss
$this.show();
} else if (!label.attr('for')) {
// Add the "for" attribute on the sibling label, matching the input's id
label.attr('for', $this.attr('id'));
}
});
}, 500));
observer.observe(document.querySelector('body'), {
childList: true,
subtree: true
});
function debounce(fn, delay) {
var timer = null;
return function() {
var me = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(me, args);
}, delay);
};
}
});
This diff is collapsed.
{
"name": "org.civicrm.shoreditch",
"version": "1.0.0",
"description": "A CiviCRM theme based on Bootstrap",
"main": "index.js",
"license": "AGPL-3.0",
"repository": {
"type": "git",
"url": "https://github.com/civicrm/org.civicrm.shoreditch"
},
"bugs": {
"url": "https://github.com/civicrm/org.civicrm.shoreditch/issues"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"precommit": "lint-staged"
},
"lint-staged": {
"*.js": [
"semistandard --fix",
"git add"
],
"*.scss": [
"stylelint --fix",
"git add"
]
},
"semistandard": {
"globals": [
"CRM",
"jQuery"
]
},
"stylelint": {
"extends": "stylelint-config-sass-guidelines",
"plugins": [
"stylelint-order",
"stylelint-scss"
],
"rules": {
"selector-class-pattern": null,
"max-nesting-depth": 3,
"no-extra-semicolons": true,
"no-duplicate-selectors": true,
"scss/dollar-variable-colon-space-after": "at-least-one-space"
}
},
"author": "",
"license": "ISC",
"devDependencies": {
"civicrm-scssroot": "git://github.com/totten/civicrm-scssroot.git#v0.1.1",
"gulp": "^3.9.0",
"gulp-postcss": "~6.1.1",
"node-sass": "3.4.2",
"gulp-sass": "^2.1.0",
"gulp-sass-bulk-import": "^0.3.2",
"gulp-strip-css-comments": "^1.2.0",
"gulp": "^4.0.0",
"gulp-postcss": "^7.0.1",
"gulp-sass": "^4.0.1",
"gulp-sass-glob": "^1.0.9",
"gulp-strip-css-comments": "^2.0.0",
"gulp-transform-selectors": "0.0.2",
"postcss-discard-duplicates": "~2.0.1",
"postcss-prefix-selector": "~1.4.0"
"husky": "^0.14.3",
"lint-staged": "^6.1.1",
"postcss-discard-duplicates": "^2.1.0",
"postcss-prefix-selector": "^1.6.0",
"semistandard": "^12.0.1",
"stylelint": "^8.4.0",
"stylelint-config-sass-guidelines": "^4.2.0",
"stylelint-order": "^0.8.1",
"stylelint-scss": "^2.5.0"
}
}
[text-angular] {
$crm-text-angular-min-height: 120px;
border: 1px solid $gray-light;
padding: 0;
.ta-editor {
border: 0 !important;
}
.form-control {
border: 0;
box-shadow: none !important;
min-height: $crm-text-angular-min-height;
&.ta-scroll-window {
height: auto;
> .ta-bind {
min-height: $crm-text-angular-min-height;
outline: 0;
}
}
}
}
[text-angular-toolbar] {
background-color: #f4f7f8;
border: 0;
margin-left: 0;
padding: 10px;
.btn {
background: transparent !important;
border: 0;
box-shadow: none;
color: $crm-copy;
padding-left: $padding-small-horizontal;
padding-right: $padding-small-horizontal;
&.active {
color: $gray-darker !important;
}
&:hover:not(:disabled) {
color: $gray-dark;
}
.fa {
font-size: $font-size-small;
font-weight: 700;
}
}
}
.ui-select-bootstrap[theme="civihr-ui-select"] {
.ui-select-bootstrap[theme='civihr-ui-select'] {
+ .input-group-btn {
.btn {
@include border-left-radius(0);
margin-left: -1px;
......@@ -10,9 +8,9 @@
&.ui-select-multiple {
min-height: $input-height-base;
padding: 2px 2px 0 2px;
padding: 2px 2px 0;
input.ui-select-search {
.ui-select-search {
height: 1.9em;
text-indent: 10px;
}
......@@ -57,9 +55,8 @@
}
}
.ui-select-container:not([theme="civihr-ui-select"]) {
.ui-select-container:not([theme='civihr-ui-select']) {
&:not(.ui-select-multiple) {
.btn {
&.ui-select-toggle {
border-color: $input-border;
......@@ -69,7 +66,7 @@
}
&:hover {
background: #FFF;
background: $crm-white;
}