mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-03 02:27:01 +00:00
themes
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,7 +9,8 @@
|
||||
/client
|
||||
/test.php
|
||||
/main.html
|
||||
/frontend/client/css/bootstrap.css
|
||||
/frontend/client/css/espo.css
|
||||
/frontend/client/css/sacura.css
|
||||
/tests/testData/cache/*
|
||||
composer.phar
|
||||
vendor/
|
||||
|
||||
18
Gruntfile.js
18
Gruntfile.js
@@ -59,22 +59,28 @@ module.exports = function (grunt) {
|
||||
final: ['build/tmp'],
|
||||
},
|
||||
less: {
|
||||
bootstrap: {
|
||||
espo: {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: {
|
||||
'frontend/client/css/bootstrap.css': 'frontend/less/espo/main.less',
|
||||
'frontend/client/css/espo.css': 'frontend/less/espo/main.less',
|
||||
},
|
||||
},
|
||||
sacura: {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: {
|
||||
'frontend/client/css/sacura.css': 'frontend/less/sacura/main.less',
|
||||
},
|
||||
},
|
||||
},
|
||||
cssmin: {
|
||||
minify: {
|
||||
files: {
|
||||
'build/tmp/client/css/espo.min.css': [
|
||||
'frontend/client/css/bootstrap.css',
|
||||
'frontend/client/css/datepicker.css',
|
||||
'frontend/client/css/jquery.timepicker.css',
|
||||
'build/tmp/client/css/espo.css': [
|
||||
'frontend/client/css/espo.css',
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -86,11 +86,12 @@ class Application
|
||||
public function runClient()
|
||||
{
|
||||
$config = $this->getContainer()->get('config');
|
||||
$themeManager = $this->getContainer()->get('themeManager');
|
||||
|
||||
$html = file_get_contents('main.html');
|
||||
$html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html);
|
||||
$html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html);
|
||||
$html = str_replace('{{stylesheet}}', $config->get('stylesheet', 'client/css/espo.min.css'), $html);
|
||||
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet(), $html);
|
||||
$html = str_replace('{{runScript}}', 'app.start();' , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
|
||||
@@ -278,6 +278,14 @@ class Container
|
||||
);
|
||||
}
|
||||
|
||||
private function loadThemeManager()
|
||||
{
|
||||
return new \Espo\Core\Utils\ThemeManager(
|
||||
$this->get('config'),
|
||||
$this->get('metadata')
|
||||
);
|
||||
}
|
||||
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->data['user'] = $user;
|
||||
|
||||
@@ -25,19 +25,19 @@ namespace Espo\Core\Utils;
|
||||
class Crypt
|
||||
{
|
||||
private $config;
|
||||
|
||||
|
||||
private $key = null;
|
||||
|
||||
|
||||
private $cryptKey = null;
|
||||
|
||||
private $iv = null;
|
||||
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->cryptKey = $config->get('cryptKey', '');
|
||||
}
|
||||
|
||||
|
||||
protected function getKey()
|
||||
{
|
||||
if (empty($this->key)) {
|
||||
@@ -53,13 +53,13 @@ class Crypt
|
||||
}
|
||||
return $this->iv;
|
||||
}
|
||||
|
||||
|
||||
public function encrypt($string)
|
||||
{
|
||||
$iv = $this->getIv();
|
||||
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->getKey(), $string, MCRYPT_MODE_CBC, $iv) . $iv);
|
||||
}
|
||||
|
||||
|
||||
public function decrypt($encryptedString)
|
||||
{
|
||||
$encryptedString = base64_decode($encryptedString);
|
||||
@@ -68,7 +68,7 @@ class Crypt
|
||||
$iv = substr($encryptedString, -16);
|
||||
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->getKey(), $string, MCRYPT_MODE_CBC, $iv));
|
||||
}
|
||||
|
||||
|
||||
public function generateKey()
|
||||
{
|
||||
return md5(uniqid());
|
||||
|
||||
52
application/Espo/Core/Utils/ThemeManager.php
Normal file
52
application/Espo/Core/Utils/ThemeManager.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
class ThemeManager
|
||||
{
|
||||
protected $config;
|
||||
|
||||
protected $metadata;
|
||||
|
||||
private $defaultName = 'Espo';
|
||||
|
||||
private $defaultStylesheet = 'Espo';
|
||||
|
||||
public function __construct(Config $config, Metadata $metadata)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->config->get('theme', $this->defaultName);
|
||||
}
|
||||
|
||||
public function getStylesheet()
|
||||
{
|
||||
return $this->metadata->get('themes.' . $this->getName() . '.stylesheet', 'client/css/espo.css');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ return array (
|
||||
'followCreatedEntities' => false,
|
||||
'b2cMode' => false,
|
||||
'restrictedMode' => false,
|
||||
'theme' => 'Espo',
|
||||
'isInstalled' => false,
|
||||
);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class ChangePassword extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
$config = $this->getConfig();
|
||||
$themeManager = $this->getThemeManager();
|
||||
|
||||
$p = $this->getEntityManager()->getRepository('PasswordChangeRequest')->where(array(
|
||||
'requestId' => $requestId
|
||||
@@ -56,10 +57,15 @@ class ChangePassword extends \Espo\Core\EntryPoints\Base
|
||||
$html = file_get_contents('main.html');
|
||||
$html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html);
|
||||
$html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html);
|
||||
$html = str_replace('{{stylesheet}}', $config->get('stylesheet', 'client/css/espo.min.css'), $html);
|
||||
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet(), $html);
|
||||
$html = str_replace('{{runScript}}', $runScript , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function getThemeManager()
|
||||
{
|
||||
return $this->getContainer()->get('themeManager');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -530,5 +530,8 @@
|
||||
"redo":"Redo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"themes": {
|
||||
"Espo": "Espo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
"assignmentEmailNotificationsEntityList": "Entities to Notify about with Email upon Assignment",
|
||||
"b2cMode": "B2C Mode",
|
||||
"disableAvatars": "Disable Avatars",
|
||||
"followCreatedEntities": "Follow Created Entities"
|
||||
"followCreatedEntities": "Follow Created Entities",
|
||||
"theme": "Theme"
|
||||
},
|
||||
"options": {
|
||||
"weekStart": {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"label": "Configuration",
|
||||
"rows": [
|
||||
[{"name": "recordsPerPage"},{"name": "recordsPerPageSmall"}],
|
||||
[{"name": "disableAvatars"},false],
|
||||
[{"name": "theme"}, {"name": "disableAvatars"}],
|
||||
[{"name": "tabList"},{"name": "quickCreateList"}]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -235,6 +235,11 @@
|
||||
},
|
||||
"adminPanelIframeUrl": {
|
||||
"type": "varchar"
|
||||
},
|
||||
"theme": {
|
||||
"type": "enum",
|
||||
"view": "Settings.Fields.Theme",
|
||||
"translation": "themes"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
application/Espo/Resources/metadata/themes/Espo.json
Normal file
3
application/Espo/Resources/metadata/themes/Espo.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"stylesheet": "client/css/espo.css"
|
||||
}
|
||||
3
application/Espo/Resources/metadata/themes/Sacura.json
Normal file
3
application/Espo/Resources/metadata/themes/Sacura.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"stylesheet": "client/css/sacura.css"
|
||||
}
|
||||
9
frontend/client/css/glam.css
Normal file
9
frontend/client/css/glam.css
Normal file
File diff suppressed because one or more lines are too long
35
frontend/client/src/views/settings/fields/theme.js
Normal file
35
frontend/client/src/views/settings/fields/theme.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
Espo.define('views/settings/fields/theme', 'views/fields/enum', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
this.params.options = Object.keys(this.getMetadata().get('themes')).sort(function (v1, v2) {
|
||||
return this.translate(v1, 'theme').localeCompare(this.translate(v2, 'theme'));
|
||||
}.bind(this));
|
||||
|
||||
Dep.prototype.setup.call(this);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -29,8 +29,11 @@ if (!empty($_GET['entryPoint'])) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$themeManager = $app->getContainer()->get('themeManager');
|
||||
|
||||
$runScript = "app.start();";
|
||||
$html = file_get_contents("frontend/main.html");
|
||||
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet() , $html);
|
||||
$html = str_replace('{{runScript}}', $runScript , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
|
||||
@@ -299,7 +299,7 @@ ul.dropdown-menu > li.checkbox:last-child {
|
||||
}
|
||||
|
||||
#login.panel > .panel-heading {
|
||||
background-color: #4A6492;
|
||||
background-color: @login-panel-heading-bg;
|
||||
padding: 0;
|
||||
margin: -2px;
|
||||
}
|
||||
@@ -792,6 +792,10 @@ img.avatar.avatar-link {
|
||||
line-height: @line-height-computed;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.note-editable blockquote {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import "misc/selectize/selectize.less";
|
||||
@import "misc/selectize/selectize.bootstrap3.less";
|
||||
@import "misc/summernote/summernote.less";
|
||||
@import "misc/summernote/summernote.less";
|
||||
@import "misc/datepicker/datepicker.less";
|
||||
@import "misc/timepicker/timepicker.less";
|
||||
@@ -9,9 +9,6 @@
|
||||
*/
|
||||
.datepicker {
|
||||
padding: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
direction: ltr;
|
||||
/*.dow {
|
||||
border-top: 1px solid #ddd !important;
|
||||
@@ -104,9 +101,6 @@
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
.table-striped .datepicker table tr td,
|
||||
@@ -132,13 +126,6 @@
|
||||
.datepicker table tr td.today.disabled,
|
||||
.datepicker table tr td.today.disabled:hover {
|
||||
background-color: #fde19a;
|
||||
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
|
||||
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
|
||||
background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
|
||||
background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
|
||||
background-image: linear-gradient(top, #fdd49a, #fdf59a);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
|
||||
border-color: #fdf59a #fdf59a #fbed50;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
@@ -300,17 +287,6 @@
|
||||
.datepicker table tr td.active.disabled,
|
||||
.datepicker table tr td.active.disabled:hover {
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: linear-gradient(top, #0088cc, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
@@ -334,7 +310,7 @@
|
||||
.datepicker table tr td.active:hover[disabled],
|
||||
.datepicker table tr td.active.disabled[disabled],
|
||||
.datepicker table tr td.active.disabled:hover[disabled] {
|
||||
background-color: #0044cc;
|
||||
background-color: @brand-primary;
|
||||
}
|
||||
.datepicker table tr td.active:active,
|
||||
.datepicker table tr td.active:hover:active,
|
||||
@@ -372,13 +348,6 @@
|
||||
.datepicker table tr td span.active.disabled,
|
||||
.datepicker table tr td span.active.disabled:hover {
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: linear-gradient(top, #0088cc, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
@@ -406,7 +375,7 @@
|
||||
.datepicker table tr td span.active:hover[disabled],
|
||||
.datepicker table tr td span.active.disabled[disabled],
|
||||
.datepicker table tr td span.active.disabled:hover[disabled] {
|
||||
background-color: #0044cc;
|
||||
background-color: @brand-primary;
|
||||
}
|
||||
.datepicker table tr td span.active:active,
|
||||
.datepicker table tr td span.active:hover:active,
|
||||
@@ -454,14 +423,8 @@
|
||||
text-align: center;
|
||||
}
|
||||
.input-daterange input:first-child {
|
||||
-webkit-border-radius: 3px 0 0 3px;
|
||||
-moz-border-radius: 3px 0 0 3px;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
.input-daterange input:last-child {
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
.input-daterange .add-on {
|
||||
display: inline-block;
|
||||
@@ -46,7 +46,8 @@
|
||||
li.ui-timepicker-selected,
|
||||
.ui-timepicker-list li:hover,
|
||||
.ui-timepicker-list .ui-timepicker-selected:hover {
|
||||
background: #1980EC; color: #fff;
|
||||
background: @brand-primary;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
li.ui-timepicker-selected .ui-timepicker-duration,
|
||||
@@ -106,3 +106,5 @@
|
||||
@zindex-popover: 1600;
|
||||
@zindex-tooltip: 1600;
|
||||
@navbar-collapse-max-height: none;
|
||||
|
||||
@login-panel-heading-bg: @navbar-inverse-bg;
|
||||
|
||||
8
frontend/less/sacura/main.less
Normal file
8
frontend/less/sacura/main.less
Normal file
@@ -0,0 +1,8 @@
|
||||
@import "../espo/bootstrap/bootstrap.less";
|
||||
@import "../espo/variables.less";
|
||||
@import "variables.less";
|
||||
@import "../espo/mixins.less";
|
||||
|
||||
@import "../espo/misc.less";
|
||||
@import "../espo/custom.less";
|
||||
@import "../espo/bootstrap/utilities.less";
|
||||
15
frontend/less/sacura/variables.less
Normal file
15
frontend/less/sacura/variables.less
Normal file
@@ -0,0 +1,15 @@
|
||||
@gray-dark: lighten(@gray-base, 25%);
|
||||
|
||||
@main-gray: #CCD9F0;
|
||||
@input-border: #CCD9F0;
|
||||
|
||||
@body-bg: #FAFBFC;
|
||||
|
||||
@brand-primary: #739BBE;
|
||||
@brand-success: #83CD77;
|
||||
|
||||
@navbar-inverse-color: #FFF;
|
||||
@navbar-inverse-bg: #BB7690;
|
||||
@navbar-inverse-link-color: #F7F7F7;
|
||||
|
||||
@login-panel-heading-bg: @brand-primary;
|
||||
@@ -26,9 +26,7 @@
|
||||
<script type="text/javascript" src="client/src/exceptions.js"></script>
|
||||
|
||||
|
||||
<link href="client/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="client/css/jquery.timepicker.css" rel="stylesheet">
|
||||
<link href="client/css/datepicker.css" rel="stylesheet">
|
||||
<link href="{{stylesheet}}" rel="stylesheet">
|
||||
|
||||
<link rel="icon" href="client/img/favicon.ico" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="client/img/favicon.ico" type="image/x-icon">
|
||||
|
||||
Reference in New Issue
Block a user