Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Colorize checkboxes depending on theming color #415

Merged
merged 7 commits into from
Jul 28, 2016
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
27 changes: 23 additions & 4 deletions apps/theming/js/settings-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,46 @@ function calculateLuminance(rgb) {
return (0.299*r + 0.587*g + 0.114*b)/255;
}

function generateRadioButton(color) {
var radioButton = '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">' +
'<path d="M8 1a7 7 0 0 0-7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0-7-7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1-6 6 6 6 0 0 1-6-6 6 6 0 0 1 6-6zm0 2a4 4 0 1 0 0 8 4 4 0 0 0 0-8z" fill="' + color + '"/></svg>';
return btoa(radioButton);
}

function preview(setting, value) {
if (setting === 'color') {
var headerClass = document.getElementById('header');
var expandDisplayNameClass = document.getElementById('expandDisplayName');
var headerAppName = headerClass.getElementsByClassName('header-appname')[0];
var textColor, icon;
var luminance = calculateLuminance(value);
var elementColor = value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

elementColor is already defined 3 lines above.


if (calculateLuminance(value) > 0.5) {
if (luminance > 0.5) {
textColor = "#000000";
icon = 'caret-dark';
} else {
textColor = "#ffffff";
icon = 'caret';
}
if (luminance>0.8) {
elementColor = '#555555';
}

headerClass.style.background = value;
headerClass.style.backgroundImage = '../img/logo-icon.svg';
expandDisplayNameClass.style.color = textColor;
headerAppName.style.color = textColor;

$(headerClass).find('.icon-caret').each(function() {
$(this).css('background-image', "url('" + OC.getRootPath() + '/core/img/actions/' + icon + ".svg')");
});
$('#previewStyles').html(
'#header .icon-caret { background-image: url(\'' + OC.getRootPath() + '/core/img/actions/' + icon + '.svg\') }' +
'input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' +
'background-image:url(\'' + OC.getRootPath() + '/core/img/actions/checkmark-white.svg\');' +
'background-color: ' + elementColor + '; background-position: center center; background-size:contain;' +
'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;}' +
'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' +
'background-image: url(\'data:image/svg+xml;base64,' + generateRadioButton(elementColor) + '\'); }'
);
}
if (setting === 'logoMime') {
console.log(setting);
Expand All @@ -87,6 +104,8 @@ function preview(setting, value) {
$(document).ready(function () {
$('#theming [data-toggle="tooltip"]').tooltip();

$('html > head').append($('<style type="text/css" id="previewStyles"></style>'));

var uploadParamsLogo = {
pasteZone: null,
dropZone: null,
Expand Down
43 changes: 27 additions & 16 deletions apps/theming/lib/controller/themingcontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,35 +214,46 @@ public function getStylesheet() {
$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
$responseCss = '';
$color = $this->config->getAppValue($this->appName, 'color');
$elementColor = Util::elementColor($color);
if($color !== '') {
$responseCss .= sprintf(
'#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: %s}',
'#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: %s}' . "\n",
$color
);
$responseCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
'background-color: %s; background-position: center center; background-size:contain;' .
'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
"}\n",
\OC::$WEBROOT,
$elementColor
);
$responseCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
'background-image: url(\'data:image/svg+xml;base64,'.Util::generateRadioButton($elementColor).'\');' .
"}\n";
}
$logo = $this->config->getAppValue($this->appName, 'logoMime');
if($logo !== '') {
$responseCss .= sprintf('#header .logo {
background-image: url(\'./logo?v='.$cacheBusterValue.'\');
background-size: contain;
}
#header .logo-icon {
background-image: url(\'./logo?v='.$cacheBusterValue.'\');
background-size: contain;
}'
$responseCss .= sprintf(
'#header .logo {' .
'background-image: url(\'./logo?v='.$cacheBusterValue.'\')' .
'background-size: contain;' .
'}' . "\n" .
'#header .logo-icon {' .
'background-image: url(\'./logo?v='.$cacheBusterValue.'\');' .
'background-size: contain;' .
'}' . "\n"
);
}
$backgroundLogo = $this->config->getAppValue($this->appName, 'backgroundMime');
if($backgroundLogo !== '') {
$responseCss .= '#body-login {
background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');
}';
$responseCss .= '#body-login {background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');}' . "\n";
}
if(Util::invertTextColor($color)) {
$responseCss .= '#header .header-appname, #expandDisplayName { color: #000000; } ';
$responseCss .= '#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); } ';
$responseCss .= '.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }';
$responseCss .= '.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }';
$responseCss .= '#header .header-appname, #expandDisplayName { color: #000000; }' . "\n";
$responseCss .= '#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); }' . "\n";
$responseCss .= '.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }' . "\n";
$responseCss .= '.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }' . "\n";
}

\OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT');
Expand Down
25 changes: 25 additions & 0 deletions apps/theming/lib/util.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ public static function invertTextColor($color) {
}
}

/**
* get color for on-page elements:
* theme color by default, grey if theme color is to bright
* @param $color
* @return string
*/
public static function elementColor($color) {
$l = self::calculateLuminance($color);
if($l>0.8) {
return '#555555';
} else {
return $color;
}
}

/**
* @param string $color rgb color value
* @return float
Expand All @@ -56,4 +71,14 @@ public static function calculateLuminance($color) {
return (0.299 * $r + 0.587 * $g + 0.114 * $b)/255;
}

/**
* @param $color
* @return string base64 encoded radio button svg
*/
public static function generateRadioButton($color) {
$radioButtonIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">' .
'<path d="M8 1a7 7 0 0 0-7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0-7-7zm0 1a6 6 0 0 1 6 6 6 6 0 0 1-6 6 6 6 0 0 1-6-6 6 6 0 0 1 6-6zm0 2a4 4 0 1 0 0 8 4 4 0 0 0 0-8z" fill="'.$color.'"/></svg>';
return base64_encode($radioButtonIcon);
}

}
21 changes: 21 additions & 0 deletions apps/theming/tests/lib/UtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,25 @@ public function testInvertTextColorEmpty() {
$invert = Util::invertTextColor('');
$this->assertEquals(false, $invert);
}

public function testElementColorDefault() {
$elementColor = Util::elementColor("#000000");
$this->assertEquals('#000000', $elementColor);
}

public function testElementColorOnBrightBackground() {
$elementColor = Util::elementColor('#ffffff');
$this->assertEquals('#555555', $elementColor);
}

public function testGenerateRadioButtonWhite() {
$button = Util::generateRadioButton('#ffffff');
$expected = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+PHBhdGggZD0iTTggMWE3IDcgMCAwIDAtNyA3IDcgNyAwIDAgMCA3IDcgNyA3IDAgMCAwIDctNyA3IDcgMCAwIDAtNy03em0wIDFhNiA2IDAgMCAxIDYgNiA2IDYgMCAwIDEtNiA2IDYgNiAwIDAgMS02LTYgNiA2IDAgMCAxIDYtNnptMCAyYTQgNCAwIDEgMCAwIDggNCA0IDAgMCAwIDAtOHoiIGZpbGw9IiNmZmZmZmYiLz48L3N2Zz4=';
$this->assertEquals($expected, $button);
}
public function testGenerateRadioButtonBlack() {
$button = Util::generateRadioButton('#000000');
$expected = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+PHBhdGggZD0iTTggMWE3IDcgMCAwIDAtNyA3IDcgNyAwIDAgMCA3IDcgNyA3IDAgMCAwIDctNyA3IDcgMCAwIDAtNy03em0wIDFhNiA2IDAgMCAxIDYgNiA2IDYgMCAwIDEtNiA2IDYgNiAwIDAgMS02LTYgNiA2IDAgMCAxIDYtNnptMCAyYTQgNCAwIDEgMCAwIDggNCA0IDAgMCAwIDAtOHoiIGZpbGw9IiMwMDAwMDAiLz48L3N2Zz4=';
$this->assertEquals($expected, $button);
}
}
129 changes: 95 additions & 34 deletions apps/theming/tests/lib/controller/ThemingControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

use OCA\Theming\Controller\ThemingController;
use OCA\Theming\Template;
use OCA\Theming\Util;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\Files\IRootFolder;
Expand Down Expand Up @@ -327,7 +328,20 @@ public function testGetStylesheetWithOnlyColor() {
->with('theming', 'backgroundMime', '')
->willReturn('');

$expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #000}', 'style', 'text/css');
$elementColor = '#000';
$expectedCss = '#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #000}' . "\n";
$expectedCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
'background-color: %s; background-position: center center; background-size:contain;' .
'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
"}\n",
\OC::$WEBROOT,
$elementColor
);
$expectedCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
'background-image: url(\'data:image/svg+xml;base64,'.Util::generateRadioButton($elementColor).'\');' .
"}\n";
$expected = new Http\DataDownloadResponse($expectedCss, 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
Expand All @@ -353,8 +367,24 @@ public function testGetStylesheetWithOnlyColorInvert() {
->method('getAppValue')
->with('theming', 'backgroundMime', '')
->willReturn('');

$expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #fff}#header .header-appname, #expandDisplayName { color: #000000; } #header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); } .searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }', 'style', 'text/css');
$elementColor = '#555555';
$expectedCss = '#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #fff}' . "\n";
$expectedCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
'background-color: %s; background-position: center center; background-size:contain;' .
'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
"}\n",
\OC::$WEBROOT,
$elementColor
);
$expectedCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
'background-image: url(\'data:image/svg+xml;base64,'.Util::generateRadioButton($elementColor).'\');' .
"}\n";
$expectedCss .= '#header .header-appname, #expandDisplayName { color: #000000; }' . "\n" .
'#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); }' . "\n" .
'.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }' . "\n" .
'.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }' . "\n";
$expected = new Http\DataDownloadResponse($expectedCss, 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
Expand All @@ -381,14 +411,15 @@ public function testGetStylesheetWithOnlyHeaderLogo() {
->with('theming', 'backgroundMime', '')
->willReturn('');

$expected = new Http\DataDownloadResponse('#header .logo {
background-image: url(\'./logo?v=0\');
background-size: contain;
}
#header .logo-icon {
background-image: url(\'./logo?v=0\');
background-size: contain;
}', 'style', 'text/css');
$expectedCss = '#header .logo {' .
'background-image: url(\'./logo?v=0\')' .
'background-size: contain;' .
'}' . "\n" .
'#header .logo-icon {' .
'background-image: url(\'./logo?v=0\');' .
'background-size: contain;' .
'}' . "\n";
$expected = new Http\DataDownloadResponse($expectedCss, 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
Expand All @@ -415,9 +446,8 @@ public function testGetStylesheetWithOnlyBackgroundLogin() {
->with('theming', 'backgroundMime', '')
->willReturn('text/svg');

$expected = new Http\DataDownloadResponse('#body-login {
background-image: url(\'./loginbackground?v=0\');
}', 'style', 'text/css');
$expectedCss = '#body-login {background-image: url(\'./loginbackground?v=0\');}' . "\n";
$expected = new Http\DataDownloadResponse($expectedCss, 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
Expand All @@ -444,16 +474,30 @@ public function testGetStylesheetWithAllCombined() {
->with('theming', 'backgroundMime', '')
->willReturn('image/png');

$expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #000}#header .logo {
background-image: url(\'./logo?v=0\');
background-size: contain;
}
#header .logo-icon {
background-image: url(\'./logo?v=0\');
background-size: contain;
}#body-login {
background-image: url(\'./loginbackground?v=0\');
}', 'style', 'text/css');
$elementColor = '#000';
$expectedCss = '#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #000}' . "\n";
$expectedCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
'background-color: %s; background-position: center center; background-size:contain;' .
'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
"}\n",
\OC::$WEBROOT,
$elementColor
);
$expectedCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
'background-image: url(\'data:image/svg+xml;base64,'.Util::generateRadioButton($elementColor).'\');' .
"}\n";
$expectedCss .= '#header .logo {' .
'background-image: url(\'./logo?v=0\')' .
'background-size: contain;' .
'}' . "\n" .
'#header .logo-icon {' .
'background-image: url(\'./logo?v=0\');' .
'background-size: contain;' .
'}' . "\n";
$expectedCss .= '#body-login {background-image: url(\'./loginbackground?v=0\');}' . PHP_EOL;

$expected = new Http\DataDownloadResponse($expectedCss, 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
Expand All @@ -479,16 +523,33 @@ public function testGetStylesheetWithAllCombinedInverted() {
->with('theming', 'backgroundMime', '')
->willReturn('image/png');

$expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #fff}#header .logo {
background-image: url(\'./logo?v=0\');
background-size: contain;
}
#header .logo-icon {
background-image: url(\'./logo?v=0\');
background-size: contain;
}#body-login {
background-image: url(\'./loginbackground?v=0\');
}#header .header-appname, #expandDisplayName { color: #000000; } #header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); } .searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }', 'style', 'text/css');
$elementColor = '#555555';
$expectedCss = '#body-user #header,#body-settings #header,#body-public #header,#body-login,.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid {background-color: #fff}' . "\n";
$expectedCss .= sprintf('input[type="checkbox"].checkbox:checked:enabled:not(.checkbox--white) + label:before {' .
'background-image:url(\'%s/core/img/actions/checkmark-white.svg\');' .
'background-color: %s; background-position: center center; background-size:contain;' .
'width:12px; height:12px; padding:0; margin:2px 6px 6px 2px; border-radius:1px;' .
"}\n",
\OC::$WEBROOT,
$elementColor
);
$expectedCss .= 'input[type="radio"].radio:checked:not(.radio--white):not(:disabled) + label:before {' .
'background-image: url(\'data:image/svg+xml;base64,'.Util::generateRadioButton($elementColor).'\');' .
"}\n";
$expectedCss .= '#header .logo {' .
'background-image: url(\'./logo?v=0\')' .
'background-size: contain;' .
'}' . PHP_EOL .
'#header .logo-icon {' .
'background-image: url(\'./logo?v=0\');' .
'background-size: contain;' .
'}' . PHP_EOL;
$expectedCss .= '#body-login {background-image: url(\'./loginbackground?v=0\');}' . PHP_EOL;
$expectedCss .= '#header .header-appname, #expandDisplayName { color: #000000; }' . PHP_EOL .
'#header .icon-caret { background-image: url(\'' . \OC::$WEBROOT . '/core/img/actions/caret-dark.svg\'); }' . PHP_EOL .
'.searchbox input[type="search"] { background: transparent url(\'' . \OC::$WEBROOT . '/core/img/actions/search.svg\') no-repeat 6px center; color: #000; }' . PHP_EOL .
'.searchbox input[type="search"]:focus,.searchbox input[type="search"]:active,.searchbox input[type="search"]:valid { color: #000; border: 1px solid rgba(0, 0, 0, .5); }' . PHP_EOL;
$expected = new Http\DataDownloadResponse($expectedCss, 'style', 'text/css');
$expected->cacheFor(3600);
@$this->assertEquals($expected, $this->themingController->getStylesheet());
}
Expand Down
Loading