diff --git a/.gitignore b/.gitignore index 3c44925a76..f775584e22 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,9 @@ /client/css/sakura-vertical.css /client/css/violet.css /client/css/violet-vertical.css +/client/css/espo-rtl.css +/client/css/hazyblue.css + /tests/unit/testData/cache/* !/tests/unit/testData/cache/.data /tests/integration/config.php diff --git a/Gruntfile.js b/Gruntfile.js index e1ab0460e7..148d3985c8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -76,6 +76,22 @@ module.exports = function (grunt) { 'client/css/espo-vertical.css': 'frontend/less/espo-vertical/main.less', } }, + espoRtl: { + options: { + yuicompress: true + }, + files: { + 'client/css/espo-rtl.css': 'frontend/less/espo-rtl/main.less' + } + }, + hazyblue: { + options: { + yuicompress: true, + }, + files: { + 'client/css/hazyblue.css': 'frontend/less/hazyblue/main.less', + } + }, sakura: { options: { yuicompress: true, diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index fb191fdde5..248160ef12 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -648,10 +648,12 @@ }, "themes": { "Espo": "Espo", + "EspoRtl": "RTL Espo", "Sakura": "Sakura", - "EspoVertical": "Espo Vertical", - "SakuraVertical": "Sakura Vertical", + "EspoVertical": "Espo sidebarred", + "SakuraVertical": "Sakura sidebarred", "Violet": "Violet", - "VioletVertical": "Violet Vertical" + "VioletVertical": "Violet sidebarred", + "Hazyblue": "Hazyblue" } } diff --git a/application/Espo/Resources/metadata/themes/EspoRtl.json b/application/Espo/Resources/metadata/themes/EspoRtl.json new file mode 100644 index 0000000000..5c223f5b74 --- /dev/null +++ b/application/Espo/Resources/metadata/themes/EspoRtl.json @@ -0,0 +1,6 @@ +{ + "stylesheet": "client/css/espo-rtl.css", + "dashboardCellHeight": 155, + "dashboardCellMargin": 19, + "navbarHeight": 44 +} \ No newline at end of file diff --git a/application/Espo/Resources/metadata/themes/Hazyblue.json b/application/Espo/Resources/metadata/themes/Hazyblue.json new file mode 100644 index 0000000000..d4e41a0e9d --- /dev/null +++ b/application/Espo/Resources/metadata/themes/Hazyblue.json @@ -0,0 +1,9 @@ +{ + "stylesheet": "client/css/hazyblue.css", + "navbarIsVertical": true, + "navbarStaticItemsHeight": 65, + "recordTopButtonsStickTop": 61, + "recordTopButtonsBlockHeight": 21, + "dashboardCellHeight": 155, + "dashboardCellMargin": 19 +} \ No newline at end of file diff --git a/client/modules/crm/res/templates/calendar/calendar.tpl b/client/modules/crm/res/templates/calendar/calendar.tpl index f4d25743f3..4abbedec62 100644 --- a/client/modules/crm/res/templates/calendar/calendar.tpl +++ b/client/modules/crm/res/templates/calendar/calendar.tpl @@ -4,7 +4,7 @@ {{#if header}}
-
+
diff --git a/client/res/templates/fields/link-parent/edit.tpl b/client/res/templates/fields/link-parent/edit.tpl index 9b7e1dce5d..f634c45144 100644 --- a/client/res/templates/fields/link-parent/edit.tpl +++ b/client/res/templates/fields/link-parent/edit.tpl @@ -4,7 +4,7 @@ {{options foreignScopeList foreignScope category='scopeNames'}} - + diff --git a/client/src/views/fields/base.js b/client/src/views/fields/base.js index 4686c32683..665a6ff619 100644 --- a/client/src/views/fields/base.js +++ b/client/src/views/fields/base.js @@ -429,7 +429,7 @@ Espo.define('views/fields/base', 'view', function (Dep) { addInlineEditLinks: function () { var $cell = this.getCellElement(); var $saveLink = $('' + this.translate('Update') + ''); - var $cancelLink = $('' + this.translate('Cancel') + '').css('margin-left', '8px'); + var $cancelLink = $('' + this.translate('Cancel') + ''); $cell.prepend($saveLink); $cell.prepend($cancelLink); $cell.find('.inline-edit-link').addClass('hidden'); diff --git a/client/src/views/main.js b/client/src/views/main.js index 962049fe35..383d108be1 100644 --- a/client/src/views/main.js +++ b/client/src/views/main.js @@ -92,7 +92,7 @@ Espo.define('views/main', 'view', function (Dep) { a.push('
' + item + '
'); }, this); - return '
' + a.join('') + '
'; + return '
' + a.join('') + '
'; }, actionShowModal: function (data) { diff --git a/client/src/views/preferences/fields/theme.js b/client/src/views/preferences/fields/theme.js index 57c6210e3d..c01d09ddde 100644 --- a/client/src/views/preferences/fields/theme.js +++ b/client/src/views/preferences/fields/theme.js @@ -32,7 +32,7 @@ Espo.define('views/preferences/fields/theme', 'views/fields/enum', function (Dep 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')); + return this.translate(v1, 'themes').localeCompare(this.translate(v2, 'themes')); }.bind(this)); this.params.options.unshift(''); diff --git a/frontend/less/espo-rtl/bootstrap-rtl/alerts-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/alerts-rtl.less new file mode 100644 index 0000000000..e0906d0ce9 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/alerts-rtl.less @@ -0,0 +1,20 @@ +// +// RTL Alerts +// -------------------------------------------------- + + +// Dismissable alerts +// +// Expand the left padding and account for the close button's positioning. + +.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. +.alert-dismissible { + padding-left: (@alert-padding + 20); + padding-right: (@alert-padding); + + // Adjust close link position + .close { + right: auto; + left: -21px; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/badges-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/badges-rtl.less new file mode 100644 index 0000000000..ba0f4292e0 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/badges-rtl.less @@ -0,0 +1,21 @@ +// +// RTL Badges +// -------------------------------------------------- + + +// Base class +.badge { + + .nav-pills > li > a > & { + margin-left: 0px; + margin-right: 3px; + } + + .list-group-item > & { + float: left; + } + .list-group-item > & + & { + margin-left: 5px; + margin-right: auto; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/bootstrap-flipped.less b/frontend/less/espo-rtl/bootstrap-rtl/bootstrap-flipped.less new file mode 100644 index 0000000000..b07d9d1982 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/bootstrap-flipped.less @@ -0,0 +1,70 @@ +// -------------------------------------------------- +// Deprecated flips for Bootstrap RTL v3.x +// Morteza Ansarinia +// http://github.com/morteza/bootstrap-rtl +// -------------------------------------------------- + +// Regular, semantically correct Bootstrap RTL +// Core variables and mixins imported from the latest original bootstrap +@import "../bootstrap/less/variables.less"; +@import "variables-rtl.less"; +@import "mixins-flipped.less"; + +// ---- Single side border-radius ---- + +.border-right-radius(@radius) { + border-bottom-left-radius: @radius; + border-top-left-radius: @radius; +} +.border-left-radius(@radius) { + border-bottom-right-radius: @radius; + border-top-right-radius: @radius; +} + +// Reset and dependencies +@import "normalize-rtl.less"; +//@import "print.less"; +//@import "glyphicons.less"; + +// Core CSS +//@import "scaffolding.less"; +@import "type-rtl.less"; +//@import "code.less"; +@import "grid-rtl.less"; +@import "tables-rtl.less"; +@import "forms-rtl.less"; +//@import "buttons.less"; + +// Components +//@import "component-animations.less"; +@import "dropdowns-rtl.less"; +@import "button-groups-rtl.less"; +@import "input-groups-rtl.less"; +@import "navs-rtl.less"; +@import "navbar-rtl.less"; +//@import "breadcrumbs.less"; +@import "pagination-rtl.less"; +@import "pager-rtl.less"; +//@import "labels.less"; +@import "badges-rtl.less"; +//@import "jumbotron.less"; +//@import "thumbnails.less"; +@import "alerts-rtl.less"; +@import "progress-bars-rtl.less"; +@import "media-rtl.less"; +@import "list-group-rtl.less"; +@import "panels-rtl.less"; +@import "responsive-embed-rtl.less"; +//@import "wells.less"; +@import "close-rtl.less"; + +// Components w/ JavaScript +@import "modals-rtl.less"; +//@import "tooltip.less"; +@import "popovers-rtl.less"; +@import "carousel-rtl.less"; + +// Utility classes +@import "utilities-rtl.less"; +//@import "responsive-utilities.less"; +@import "flipped.less"; diff --git a/frontend/less/espo-rtl/bootstrap-rtl/bootstrap-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/bootstrap-rtl.less new file mode 100644 index 0000000000..7d0219903d --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/bootstrap-rtl.less @@ -0,0 +1,57 @@ +// -------------------------------------------------- +// Right-to-Left (RTL) Theme for Bootstrap 3.x +// Morteza Ansarinia +// http://github.com/morteza/bootstrap-rtl +// -------------------------------------------------- + +// Core variables and mixins imported from the latest original bootstrap +@import "../../espo/bootstrap/variables.less"; +@import "variables-rtl.less"; +@import "mixins-rtl.less"; + +// Reset and dependencies +@import "normalize-rtl.less"; +//@import "print.less"; +//@import "glyphicons.less"; + +// Core CSS +//@import "scaffolding.less"; +@import "type-rtl.less"; +//@import "code.less"; +@import "grid-rtl.less"; +@import "tables-rtl.less"; +@import "forms-rtl.less"; +//@import "buttons.less"; + +// Components +//@import "component-animations.less"; +@import "dropdowns-rtl.less"; +@import "button-groups-rtl.less"; +@import "input-groups-rtl.less"; +@import "navs-rtl.less"; +@import "navbar-rtl.less"; +//@import "breadcrumbs.less"; +@import "pagination-rtl.less"; +@import "pager-rtl.less"; +//@import "labels.less"; +@import "badges-rtl.less"; +//@import "jumbotron.less"; +//@import "thumbnails.less"; +@import "alerts-rtl.less"; +@import "progress-bars-rtl.less"; +@import "media-rtl.less"; +@import "list-group-rtl.less"; +@import "panels-rtl.less"; +@import "responsive-embed-rtl.less"; +//@import "wells.less"; +@import "close-rtl.less"; + +// Components w/ JavaScript +@import "modals-rtl.less"; +//@import "tooltip.less"; +@import "popovers-rtl.less"; +@import "carousel-rtl.less"; + +// Utility classes +@import "utilities-rtl.less"; +//@import "responsive-utilities.less"; diff --git a/frontend/less/espo-rtl/bootstrap-rtl/button-groups-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/button-groups-rtl.less new file mode 100644 index 0000000000..c4e2fa1af2 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/button-groups-rtl.less @@ -0,0 +1,102 @@ +// +// RTL Button groups +// -------------------------------------------------- + +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + > .btn { + float: right; + } +} + +// Prevent double borders when buttons are next to each other +.btn-group { + .btn + .btn, + .btn + .btn-group, + .btn-group + .btn, + .btn-group + .btn-group { + margin-right: -1px; + margin-left: 0px; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + margin-right: -5px; // Offset the first child's margin + margin-left: 0px; + + .btn-group, + .input-group { + float: right; + } + > .btn, + > .btn-group, + > .input-group { + margin-right: 5px; + margin-left: 0px; + } +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-right: 0; + &:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: @border-radius-base; + border-bottom-right-radius: @border-radius-base; + .border-left-radius(0); + } +} +// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-top-left-radius: @border-radius-base; + border-bottom-left-radius: @border-radius-base; + .border-right-radius(0); +} + +// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) +.btn-group > .btn-group { + float: right; +} + +.btn-group.btn-group-justified > .btn, +.btn-group.btn-group-justified > .btn-group { + float: none; +} + +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child { + > .btn:last-child, + > .dropdown-toggle { + border-top-right-radius: @border-radius-base; + border-bottom-right-radius: @border-radius-base; + .border-left-radius(0); + } +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-top-left-radius: @border-radius-base; + border-bottom-left-radius: @border-radius-base; + .border-right-radius(0); +} + +// Reposition the caret +.btn .caret { + margin-right: 0; +} + +// Vertical button groups +// ---------------------- + +.btn-group-vertical { + + > .btn + .btn, + > .btn + .btn-group, + > .btn-group + .btn, + > .btn-group + .btn-group { + margin-top: -1px; + margin-right: 0; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/carousel-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/carousel-rtl.less new file mode 100644 index 0000000000..e5650ae1f6 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/carousel-rtl.less @@ -0,0 +1,76 @@ +// +// RTL Carousel +// -------------------------------------------------- + + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + right: 0; + bottom: 0; + + // Set gradients for backgrounds + &.left { + right: auto; + left: 0; + #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001)); + } + &.right { + left: auto; + right: 0; + #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5)); + } + + .icon-prev, + .glyphicon-chevron-left { + left: 50%; + right: auto; + margin-right: -10px; + } + .icon-next, + .glyphicon-chevron-right { + right: 50%; + left: auto; + margin-left: -10px; + } +} + +// Optional indicator pips +// +// Add an unordered list with the following class and add a list item for each +// slide your carousel holds. + +.carousel-indicators { + right: 50%; + left: 0; + margin-right: -30%; + margin-left: 0; + padding-left: 0; + +} + +// Scale up controls for tablets and up +@media screen and (min-width: @screen-sm-min) { + + // Scale up the controls a smidge + .carousel-control { + .glyphicon-chevron-left, + .icon-prev { + margin-left: 0; + margin-right: -15px; + } + .glyphicon-chevron-right, + .icon-next { + margin-left: 0; + margin-right: -15px; + } + } + + // Show and left align the captions + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/close-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/close-rtl.less new file mode 100644 index 0000000000..b61439574c --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/close-rtl.less @@ -0,0 +1,8 @@ +// +// RTL Close icons +// -------------------------------------------------- + + +.close { + float: left; +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/dropdowns-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/dropdowns-rtl.less new file mode 100644 index 0000000000..808252c7fb --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/dropdowns-rtl.less @@ -0,0 +1,63 @@ +// +// RTL Dropdown menus +// -------------------------------------------------- + +// Dropdown arrow/caret +.caret { + margin-right: 2px; + margin-left: 0; +} + +// The dropdown menu (ul) +.dropdown-menu { + right: auto; + left: 0; + float: left; + text-align: right; // Ensures proper alignment if parent has it changed (e.g., modal footer) + + // Aligns the dropdown menu to right + // + // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]` + &.pull-right { + left: 0; + right: auto; + float: right; + } +} + +// Menu positioning +// +// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown +// menu with the parent. +.dropdown-menu-right { + left: auto; // Reset the default from `.dropdown-menu` + right: 0; +} +// With v3, we enabled auto-flipping if you have a dropdown within a right +// aligned nav component. To enable the undoing of that, we provide an override +// to restore the default dropdown menu alignment. +// +// This is only for left-aligning a dropdown menu within a `.navbar-right` or +// `.pull-right` nav component. +.dropdown-menu-left { + left: 0; + right: auto; +} + +// Component alignment +// +// Reiterate per navbar.less and the modified component alignment there. + +@media (min-width: @grid-float-breakpoint) { + .navbar-right { + .dropdown-menu { + .dropdown-menu-right(); + } + // Necessary for overrides of the default right aligned menu. + // Will remove come v4 in all likelihood. + .dropdown-menu-left { + .dropdown-menu-left(); + } + } +} + diff --git a/frontend/less/espo-rtl/bootstrap-rtl/flipped.less b/frontend/less/espo-rtl/bootstrap-rtl/flipped.less new file mode 100644 index 0000000000..fb5d26f228 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/flipped.less @@ -0,0 +1,85 @@ +// --------------------------------------------- +// Flipped classes +// --------------------------------------------- + +// ---- Utilities ---- +.pull-right { + float: left !important; +} +.pull-left { + float: right !important; +} + +//TODO carousel +//TODO Glyphicons + +// ---- Dropdown ---- +.dropdown-menu-left { + left: auto; + right: 0; +} + +// ---- Media ---- +.media-right, +.media > .pull-right { + padding-right: 10px; + padding-left: initial; +} + +.media-left, +.media > .pull-left { + padding-left: 10px; + padding-right: initial; +} + +// ---- Navbar ---- +@media (min-width: @grid-float-breakpoint) { + .navbar-left { .pull-left(); } + .navbar-right { + .pull-right(); + margin-left: -@navbar-padding-horizontal; + margin-right: initial; + + ~ .navbar-right { + margin-left: 0; + margin-right: initial; + } + } +} + +// ---- Tooltip ---- +.tooltip { + &.top-left .tooltip-arrow { + left: @tooltip-arrow-width; + } + &.top-right .tooltip-arrow { + right: @tooltip-arrow-width; + } + &.right .tooltip-arrow { + right: 0; + border-left-color: @tooltip-arrow-color; + } + &.left .tooltip-arrow { + left: 0; + border-right-color: @tooltip-arrow-color; + } + &.bottom-left .tooltip-arrow { + left: @tooltip-arrow-width; + } + &.bottom-right .tooltip-arrow { + right: @tooltip-arrow-width; + } +} + +// ---- Type ---- +.text-left { text-align: right; } +.text-right { text-align: left; } + +//DEPRECATED +blockquote.pull-right { + padding-left: 15px; + padding-right: 0; + border-left: 5px solid @blockquote-border-color; + border-right: 0; + text-align: left; +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/forms-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/forms-rtl.less new file mode 100644 index 0000000000..3a91b9cfe2 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/forms-rtl.less @@ -0,0 +1,102 @@ +// +// RTL Forms +// -------------------------------------------------- + + +.radio, +.checkbox { + + label { + padding-right: 20px; + padding-left: initial; + } +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + margin-right: -20px; + margin-left: auto; +} + +// Radios and checkboxes on same line +.radio-inline, +.checkbox-inline { + padding-right: 20px; + padding-left: 0; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-right: 10px; // space out consecutive inline controls + margin-left: 0; +} + +.has-feedback { + + // Ensure icons don't overlap text + .form-control { + padding-left: (@input-height-base * 1.25); + padding-right: 12px; + } +} +// Feedback icon (requires .glyphicon classes) +.form-control-feedback { + left: 0; + right: auto; +} + +// Inline forms +// +// Make forms appear inline(-block) by adding the `.form-inline` class. Inline +// forms begin stacked on extra small (mobile) devices and then go inline when +// viewports reach <768px. +// +// Requires wrapping inputs and labels with `.form-group` for proper display of +// default HTML form controls and our custom form controls (e.g., input groups). +// +// Heads up! This is mixin-ed into `.navbar-form` in navbars.less. + +.form-inline { + + // Kick in the inline + @media (min-width: @screen-sm-min) { + + label { + padding-right: 0; + padding-left: initial; + } + + .radio input[type="radio"], + .checkbox input[type="checkbox"] { + margin-right: 0; + margin-left: auto; + } + + } +} + + +// Horizontal forms +// +// Horizontal forms are built on grid classes and allow you to create forms with +// labels on the left and inputs on the right. + +.form-horizontal { + + // Reset spacing and right align labels, but scope to media queries so that + // labels on narrow viewports stack the same as a default form example. + @media (min-width: @screen-sm-min) { + .control-label { + text-align: left; + } + } + + // Validation states + // + // Reposition the icon because it's now within a grid column and columns have + // `position: relative;` on them. Also accounts for the grid gutter padding. + .has-feedback .form-control-feedback { + left: (@grid-gutter-width / 2); + right: auto; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/grid-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/grid-rtl.less new file mode 100644 index 0000000000..e482bcbf6d --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/grid-rtl.less @@ -0,0 +1,45 @@ +// +// RTL Grid system +// -------------------------------------------------- + +// Columns +// +// Common styles for small and large grid columns + +.make-rtl-grid-columns(); + + +// Extra small grid +// +// Columns, offsets, pushes, and pulls for extra small devices like +// smartphones. + +.make-rtl-grid(xs); + + +// Small grid +// +// Columns, offsets, pushes, and pulls for the small device range, from phones +// to tablets. + +@media (min-width: @screen-sm-min) { + .make-rtl-grid(sm); +} + + +// Medium grid +// +// Columns, offsets, pushes, and pulls for the desktop device range. + +@media (min-width: @screen-md-min) { + .make-rtl-grid(md); +} + + +// Large grid +// +// Columns, offsets, pushes, and pulls for the large desktop device range. + +@media (min-width: @screen-lg-min) { + .make-rtl-grid(lg); +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/input-groups-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/input-groups-rtl.less new file mode 100644 index 0000000000..31cc265614 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/input-groups-rtl.less @@ -0,0 +1,76 @@ +// +// Input groups +// -------------------------------------------------- + +// Base styles +// ------------------------- +.input-group { + .form-control { + // IE9 fubars the placeholder attribute in text inputs and the arrows on + // select elements in input groups. To fix it, we float the input. Details: + // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855 + float: right; + } +} + +// Reset rounded corners +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + .border-right-radius(@border-radius-base); + .border-left-radius(0); +} +.input-group-addon:first-child { + border-left: 0px; + border-right: 1px solid; +} + +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + .border-left-radius(@border-radius-base); + .border-right-radius(0); +} +.input-group-addon:last-child { + border-left-width: 1px; + border-left-style: solid; + border-right: 0px; +} + +// Button input groups +// ------------------------- +.input-group-btn { + + // Negative margin for spacing, position for bringing hovered/focused/actived + // element above the siblings. + > .btn { + + .btn { + margin-right: -1px; + margin-left: auto; + } + } + + // Negative margin to only have a 1px border between the two + &:first-child { + > .btn, + > .btn-group { + margin-left: -1px; + margin-right: auto; + } + } + &:last-child { + > .btn, + > .btn-group { + margin-right: -1px; + margin-left: auto; + } + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/list-group-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/list-group-rtl.less new file mode 100644 index 0000000000..67734f7e44 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/list-group-rtl.less @@ -0,0 +1,14 @@ +// +// List groups +// -------------------------------------------------- + + +// Base class +// +// Easily usable on
    ,
      , or
      . + +.list-group { + padding-right: 0; // reset padding because ul and ol + padding-left: initial; +} + diff --git a/frontend/less/espo-rtl/bootstrap-rtl/media-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/media-rtl.less new file mode 100644 index 0000000000..9dd84247ff --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/media-rtl.less @@ -0,0 +1,47 @@ +// RTL Media objects +// -------------------------------------------------- + + +// Media image alignment +// ------------------------- + +.media { + > .pull-left { + margin-right: 10px; + &.flip { + margin-right: 0; + margin-left: 10px; + } + } + > .pull-right { + margin-left: 10px; + &.flip { + margin-left: 0; + margin-right: 10px; + } + } +} + +.media-right, +.media > .pull-right { + padding-right: 10px; + padding-left: initial; +} + +.media-left, +.media > .pull-left { + padding-left: 10px; + padding-right: initial; +} + + +// Media list variation +// ------------------------- + +// Undo default ul/ol styles +.media-list { + padding-right: 0; + padding-left: initial; + list-style: none; +} + diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins-flipped.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins-flipped.less new file mode 100644 index 0000000000..8c5d1e715f --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins-flipped.less @@ -0,0 +1,39 @@ +// Mixins +// -------------------------------------------------- + +// Utilities +@import "../bootstrap/less/mixins/hide-text.less"; +@import "../bootstrap/less/mixins/opacity.less"; +@import "../bootstrap/less/mixins/image.less"; +@import "../bootstrap/less/mixins/labels.less"; +@import "../bootstrap/less/mixins/reset-filter.less"; +@import "../bootstrap/less/mixins/resize.less"; +@import "../bootstrap/less/mixins/responsive-visibility.less"; +@import "../bootstrap/less/mixins/size.less"; +@import "../bootstrap/less/mixins/tab-focus.less"; +@import "../bootstrap/less/mixins/text-emphasis.less"; +@import "../bootstrap/less/mixins/text-overflow.less"; +@import "../bootstrap/less/mixins/vendor-prefixes.less"; + +// Components +@import "../bootstrap/less/mixins/alerts.less"; +@import "../bootstrap/less/mixins/buttons.less"; +@import "../bootstrap/less/mixins/panels.less"; +@import "mixins/pagination-rtl.less"; // RTL +@import "../bootstrap/less/mixins/list-group.less"; +@import "../bootstrap/less/mixins/nav-divider.less"; +@import "../bootstrap/less/mixins/forms.less"; +@import "../bootstrap/less/mixins/progress-bar.less"; +@import "../bootstrap/less/mixins/table-row.less"; + +// Skins +@import "../bootstrap/less/mixins/background-variant.less"; +@import "mixins/border-radius-flipped.less"; //FLIPPED +@import "mixins/gradients-rtl.less"; // RTL + +// Layout +@import "../bootstrap/less/mixins/clearfix.less"; +@import "../bootstrap/less/mixins/center-block.less"; +@import "../bootstrap/less/mixins/nav-vertical-align.less"; +@import "mixins/grid-framework-rtl.less"; // RTL +@import "mixins/grid-rtl.less"; // RTL diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins-rtl.less new file mode 100644 index 0000000000..e8c121ba2d --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins-rtl.less @@ -0,0 +1,39 @@ +// Mixins +// -------------------------------------------------- + +// Utilities +@import "../../espo/bootstrap/mixins/hide-text.less"; +@import "../../espo/bootstrap/mixins/opacity.less"; +@import "../../espo/bootstrap/mixins/image.less"; +@import "../../espo/bootstrap/mixins/labels.less"; +@import "../../espo/bootstrap/mixins/reset-filter.less"; +@import "../../espo/bootstrap/mixins/resize.less"; +@import "../../espo/bootstrap/mixins/responsive-visibility.less"; +@import "../../espo/bootstrap/mixins/size.less"; +@import "../../espo/bootstrap/mixins/tab-focus.less"; +@import "../../espo/bootstrap/mixins/text-emphasis.less"; +@import "../../espo/bootstrap/mixins/text-overflow.less"; +@import "../../espo/bootstrap/mixins/vendor-prefixes.less"; + +// Components +@import "../../espo/bootstrap/mixins/alerts.less"; +@import "../../espo/bootstrap/mixins/buttons.less"; +@import "../../espo/bootstrap/mixins/panels.less"; +@import "mixins/pagination-rtl.less"; // RTL +@import "../../espo/bootstrap/mixins/list-group.less"; +@import "../../espo/bootstrap/mixins/nav-divider.less"; +@import "../../espo/bootstrap/mixins/forms.less"; +@import "../../espo/bootstrap/mixins/progress-bar.less"; +@import "../../espo/bootstrap/mixins/table-row.less"; + +// Skins +@import "../../espo/bootstrap/mixins/background-variant.less"; +@import "../../espo/bootstrap/mixins/border-radius.less"; +@import "mixins/gradients-rtl.less"; // RTL + +// Layout +@import "../../espo/bootstrap/mixins/clearfix.less"; +@import "../../espo/bootstrap/mixins/center-block.less"; +@import "../../espo/bootstrap/mixins/nav-vertical-align.less"; +@import "mixins/grid-framework-rtl.less"; // RTL +@import "mixins/grid-rtl.less"; // RTL diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins/border-radius-flipped.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins/border-radius-flipped.less new file mode 100644 index 0000000000..bddaeca3b8 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins/border-radius-flipped.less @@ -0,0 +1,10 @@ +// Single side flipped border-radius + +.border-right-radius(@radius) { + border-bottom-left-radius: @radius; + border-top-left-radius: @radius; +} +.border-left-radius(@radius) { + border-bottom-right-radius: @radius; + border-top-right-radius: @radius; +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins/gradients-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins/gradients-rtl.less new file mode 100644 index 0000000000..3a69ad9797 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins/gradients-rtl.less @@ -0,0 +1,24 @@ +// RTL Gradients + +#gradient { + + // Horizontal gradient, from right to left + // + // Creates two color stops, start and end, by specifying a color and position for each color stop. + // Color stops are not available in IE9 and below. + .horizontal(@start-color: #333; @end-color: #555; @start-percent: 0%; @end-percent: 100%) { + background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12 + background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down + } + + .horizontal-three-colors(@start-color: #c3325f; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #00b3ee) { + background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color); + background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color); + background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins/grid-framework-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins/grid-framework-rtl.less new file mode 100644 index 0000000000..fd736be24c --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins/grid-framework-rtl.less @@ -0,0 +1,96 @@ +// RTL Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `@grid-columns`. + +.make-rtl-grid-columns() { + // Common styles for all sizes of grid columns, widths 1-12 + .col(@index) { // initial + @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}"; + .col((@index + 1), @item); + } + .col(@index, @list) when (@index =< @grid-columns) { // general; "=<" isn't a typo + @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}"; + .col((@index + 1), ~"@{list}, @{item}"); + } + .col(@index, @list) when (@index > @grid-columns) { // terminal + @{list} { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: (@grid-gutter-width / 2); + padding-right: (@grid-gutter-width / 2); + } + } + .col(1); // kickstart it +} + +.float-rtl-grid-columns(@class) { + .col(@index) { // initial + @item: ~".col-@{class}-@{index}"; + .col((@index + 1), @item); + } + .col(@index, @list) when (@index =< @grid-columns) { // general + @item: ~".col-@{class}-@{index}"; + .col((@index + 1), ~"@{list}, @{item}"); + } + .col(@index, @list) when (@index > @grid-columns) { // terminal + @{list} { + float: right; + } + } + .col(1); // kickstart it +} + +.calc-rtl-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) { + .col-@{class}-@{index} { + width: percentage((@index / @grid-columns)); + } +} +.calc-rtl-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) { + .col-@{class}-push-@{index} { + right: percentage((@index / @grid-columns)); + left: 0; + } +} +.calc-rtl-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) { + .col-@{class}-push-0 { + right: auto; + left: 0; + } +} +.calc-rtl-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) { + .col-@{class}-pull-@{index} { + left: percentage((@index / @grid-columns)); + right: auto; + } +} +.calc-rtl-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) { + .col-@{class}-pull-0 { + left: auto; + right: auto; + } +} +.calc-rtl-grid-column(@index, @class, @type) when (@type = offset) { + .col-@{class}-offset-@{index} { + margin-right: percentage((@index / @grid-columns)); + margin-left: 0; + } +} + +// Basic looping in LESS +.loop-rtl-grid-columns(@index, @class, @type) when (@index >= 0) { + .calc-rtl-grid-column(@index, @class, @type); + // next iteration + .loop-rtl-grid-columns((@index - 1), @class, @type); +} + +// Create grid for specific class +.make-rtl-grid(@class) { + .float-rtl-grid-columns(@class); + .loop-rtl-grid-columns(@grid-columns, @class, width); + .loop-rtl-grid-columns(@grid-columns, @class, pull); + .loop-rtl-grid-columns(@grid-columns, @class, push); + .loop-rtl-grid-columns(@grid-columns, @class, offset); +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins/grid-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins/grid-rtl.less new file mode 100644 index 0000000000..f6e186983e --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins/grid-rtl.less @@ -0,0 +1,98 @@ +// RTL Grid system +// +// Generate semantic rtl grid columns with these mixins. + +// Generate the extra small columns +.make-xs-column(@columns; @gutter: @grid-gutter-width) { + float: right; +} +.make-xs-column-offset(@columns) { + margin-right: percentage((@columns / @grid-columns)); + margin-left: 0; +} +.make-xs-column-push(@columns) { + right: percentage((@columns / @grid-columns)); + left: auto; +} +.make-xs-column-pull(@columns) { + left: percentage((@columns / @grid-columns)); + right: auto; +} + +// Generate the small columns +.make-sm-column(@columns; @gutter: @grid-gutter-width) { + + @media (min-width: @screen-sm-min) { + float: right; + } +} +.make-sm-column-offset(@columns) { + @media (min-width: @screen-sm-min) { + margin-right: percentage((@columns / @grid-columns)); + margin-left: 0; + } +} +.make-sm-column-push(@columns) { + @media (min-width: @screen-sm-min) { + right: percentage((@columns / @grid-columns)); + left: auto; + } +} +.make-sm-column-pull(@columns) { + @media (min-width: @screen-sm-min) { + left: percentage((@columns / @grid-columns)); + right: auto; + } +} + +// Generate the medium columns +.make-md-column(@columns; @gutter: @grid-gutter-width) { + + @media (min-width: @screen-md-min) { + float: right; + } +} +.make-md-column-offset(@columns) { + @media (min-width: @screen-md-min) { + margin-right: percentage((@columns / @grid-columns)); + margin-left: 0; + } +} +.make-md-column-push(@columns) { + @media (min-width: @screen-md-min) { + right: percentage((@columns / @grid-columns)); + left: auto; + } +} +.make-md-column-pull(@columns) { + @media (min-width: @screen-md-min) { + left: percentage((@columns / @grid-columns)); + right: auto; + } +} + +// Generate the large columns +.make-lg-column(@columns; @gutter: @grid-gutter-width) { + + @media (min-width: @screen-lg-min) { + float: right; + } +} +.make-lg-column-offset(@columns) { + @media (min-width: @screen-lg-min) { + margin-right: percentage((@columns / @grid-columns)); + margin-left: 0; + } +} +.make-lg-column-push(@columns) { + @media (min-width: @screen-lg-min) { + right: percentage((@columns / @grid-columns)); + left: auto; + } +} +.make-lg-column-pull(@columns) { + @media (min-width: @screen-lg-min) { + left: percentage((@columns / @grid-columns)); + right: auto; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/mixins/pagination-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/mixins/pagination-rtl.less new file mode 100644 index 0000000000..92c3a234ec --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/mixins/pagination-rtl.less @@ -0,0 +1,18 @@ +// Pagination + +.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) { + > li { + &:first-child { + > a, + > span { + .border-right-radius(@border-radius); + } + } + &:last-child { + > a, + > span { + .border-left-radius(@border-radius); + } + } + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/modals-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/modals-rtl.less new file mode 100644 index 0000000000..0a373c8385 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/modals-rtl.less @@ -0,0 +1,27 @@ +// +// RTL Modals +// -------------------------------------------------- + +// Footer (for actions) +.modal-footer { + text-align: left; // right align buttons + + &.flip { + text-align: right; + } + // Properly space out buttons + .btn + .btn { + margin-left: auto; + margin-right: 5px; + } + // but override that for button groups + .btn-group .btn + .btn { + margin-right: -1px; + margin-left: auto; + } + // and override it for block buttons as well + .btn-block + .btn-block { + margin-right: 0; + margin-left: auto; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/navbar-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/navbar-rtl.less new file mode 100644 index 0000000000..792376cf1b --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/navbar-rtl.less @@ -0,0 +1,135 @@ +// +// RTL Navbars +// -------------------------------------------------- + + +// Navbar heading +// +// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy +// styling of responsive aspects. + +.navbar-header { + + @media (min-width: @grid-float-breakpoint) { + float: right; + } +} + + +// Navbar collapse (body) +// +// Group your navbar content into this for easy collapsing and expanding across +// various device sizes. By default, this content is collapsed when <768px, but +// will expand past that for a horizontal display. +// +// To start (on mobile devices) the navbar links, forms, and buttons are stacked +// vertically and include a `max-height` to overflow in case you have too much +// content for the user's viewport. + +.navbar-collapse { + padding-right: @navbar-padding-horizontal; + padding-left: @navbar-padding-horizontal; +} + + +// Brand/project name + +.navbar-brand { + float: right; + + @media (min-width: @grid-float-breakpoint) { + .navbar > .container &, + .navbar > .container-fluid & { + margin-right: -@navbar-padding-horizontal; + margin-left: auto; + } + } +} + + +// Navbar toggle +// +// Custom button for toggling the `.navbar-collapse`, powered by the collapse +// JavaScript plugin. + +.navbar-toggle { + float: left; + margin-left: @navbar-padding-horizontal; + margin-right: auto; +} + + +// Navbar nav links +// +// Builds on top of the `.nav` components with its own modifier class to make +// the nav the full height of the horizontal nav (above 768px). + +.navbar-nav { + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display when collapsed + .open .dropdown-menu { + > li > a, + .dropdown-header { + padding: 5px 25px 5px 15px; + } + } + } + + // Uncollapse the nav + @media (min-width: @grid-float-breakpoint) { + float: right; + + > li { + float: right !important; + } + + } +} + +@media (min-width: @grid-float-breakpoint) { + .navbar-left { + float: right !important; + &.flip { + float: right !important; + } + } + + .navbar-right { + float: left !important; + &:last-child { + margin-left: -@navbar-padding-horizontal; + margin-right: auto; + } + + &.flip { + float: left !important; + margin-left: -@navbar-padding-horizontal; + margin-right: auto; + } + + .dropdown-menu { + left: 0; + right: auto; + } + } +} + +// Text in navbars +// +// Add a class to make any element properly align itself vertically within the navbars. + +.navbar-text { + + @media (min-width: @grid-float-breakpoint) { + float: right; + + // Outdent the form if last child to line up with content down the page + &.navbar-right:last-child { + margin-left: 0; + margin-right: auto; + } + } +} + + diff --git a/frontend/less/espo-rtl/bootstrap-rtl/navs-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/navs-rtl.less new file mode 100644 index 0000000000..6810031094 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/navs-rtl.less @@ -0,0 +1,97 @@ +// +// Navs +// -------------------------------------------------- + + +// Base class +// -------------------------------------------------- + +.nav { + padding-right: 0; // Override default ul/ol + padding-left: initial; +} + + +// Tabs +// ------------------------- + +// Give the tabs something to sit on +.nav-tabs { + > li { + float: right; + + // Actual tabs (as links) + > a { + margin-left: auto; + margin-right: -2px; + border-radius: @border-radius-base @border-radius-base 0 0; + } + } +} + + +// Pills +// ------------------------- +.nav-pills { + > li { + float: right; + + // Links rendered as pills + > a { + border-radius: @nav-pills-border-radius; + } + + li { + margin-right: 2px; + margin-left: auto; + } + } +} + + +// Stacked pills +.nav-stacked { + > li { + float: none; + + li { + margin-right: 0; // no need for this gap between nav items + margin-left: auto; + } + } +} + + +// Nav variations +// -------------------------------------------------- + +// Justified nav links +// ------------------------- + +.nav-justified { + + //To fix the overridden style by line 21 + > li{ + float: none; + } + + > .dropdown .dropdown-menu { + right: auto; + } +} + +// Move borders to anchors instead of bottom of list +// +// Mixin for adding on top the shared `.nav-justified` styles for our tabs +.nav-tabs-justified { + + > li > a { + // Override margin from .nav-tabs + margin-left: 0; + margin-right: auto; + } + + @media (min-width: @screen-sm-min) { + > li > a { + border-radius: @border-radius-base @border-radius-base 0 0; + } + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/normalize-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/normalize-rtl.less new file mode 100644 index 0000000000..c1250b9e7e --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/normalize-rtl.less @@ -0,0 +1,15 @@ +// +// 1. Set direction to RTL +// + +html { + direction: rtl; +} + +// +// Remove default margin. +// + +body { + direction: rtl; +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/pager-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/pager-rtl.less new file mode 100644 index 0000000000..b00b3b0540 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/pager-rtl.less @@ -0,0 +1,24 @@ +// +// RTL Pager pagination +// -------------------------------------------------- + + +.pager { + padding-right: 0; + padding-left: initial; + + .next { + > a, + > span { + float: left; + } + } + + .previous { + > a, + > span { + float: right; + } + } + +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/pagination-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/pagination-rtl.less new file mode 100644 index 0000000000..04355eb5a7 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/pagination-rtl.less @@ -0,0 +1,32 @@ +// +// RTL Pagination (multiple pages) +// -------------------------------------------------- +.pagination { + padding-right: 0; + + > li { + > a, + > span { + float: right; // Collapse white-space + margin-right: -1px; + margin-left: 0px; + } + &:first-child { + > a, + > span { + margin-left: 0; + .border-right-radius(@border-radius-base); + .border-left-radius(0); + } + } + &:last-child { + > a, + > span { + margin-right: -1px; + .border-left-radius(@border-radius-base); + .border-right-radius(0); + } + } + } + +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/panels-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/panels-rtl.less new file mode 100644 index 0000000000..a686b9feea --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/panels-rtl.less @@ -0,0 +1,70 @@ +// +// RTL Panels +// -------------------------------------------------- + +// Tables in panels +// +// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and +// watch it go full width. + +.panel { + // Add border top radius for first one + > .table:first-child, + > .table-responsive:first-child > .table:first-child { + + > thead:first-child, + > tbody:first-child { + > tr:first-child { + td:first-child, + th:first-child { + border-top-right-radius: (@panel-border-radius - 1); + border-top-left-radius: 0; + } + td:last-child, + th:last-child { + border-top-left-radius: (@panel-border-radius - 1); + border-top-right-radius: 0; + } + } + } + } + // Add border bottom radius for last one + > .table:last-child, + > .table-responsive:last-child > .table:last-child { + + > tbody:last-child, + > tfoot:last-child { + > tr:last-child { + td:first-child, + th:first-child { + border-bottom-left-radius: (@panel-border-radius - 1); + border-top-right-radius: 0; + } + td:last-child, + th:last-child { + border-bottom-right-radius: (@panel-border-radius - 1); + border-top-left-radius: 0; + } + } + } + } + > .table-bordered, + > .table-responsive > .table-bordered { + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-right: 0; + border-left: none; + } + > th:last-child, + > td:last-child { + border-right: none; + border-left: 0; + } + } + } + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/popovers-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/popovers-rtl.less new file mode 100644 index 0000000000..ce62b02e13 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/popovers-rtl.less @@ -0,0 +1,33 @@ +// +// Popovers +// -------------------------------------------------- + + +.popover { + left: auto; + text-align: right; +} + +.popover { + &.top > .arrow { + right: 50%; + left: auto; + margin-right: -@popover-arrow-outer-width; + margin-left: auto; + &:after { + margin-right: -@popover-arrow-width; + margin-left: auto; + } + } + &.bottom > .arrow { + right: 50%; + left: auto; + margin-right: -@popover-arrow-outer-width; + margin-left: auto; + &:after { + margin-right: -@popover-arrow-width; + margin-left: auto; + } + } + +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/progress-bars-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/progress-bars-rtl.less new file mode 100644 index 0000000000..9b5b9f76e0 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/progress-bars-rtl.less @@ -0,0 +1,8 @@ +// +// RTL Progress bars +// -------------------------------------------------- + +// Bar of progress +.progress-bar { + float: right; +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/responsive-embed-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/responsive-embed-rtl.less new file mode 100644 index 0000000000..87bc416db0 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/responsive-embed-rtl.less @@ -0,0 +1,15 @@ +// RTL Embeds responsive +// +// Credit: Nicolas Gallagher and SUIT CSS. + +.embed-responsive { + + .embed-responsive-item, + iframe, + embed, + object { + right: 0; + left: auto; + } + +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/tables-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/tables-rtl.less new file mode 100644 index 0000000000..956e6ade46 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/tables-rtl.less @@ -0,0 +1,47 @@ +// +// Tables +// -------------------------------------------------- + +//TODO +caption { + text-align: right; +} + +th { + text-align: right; +} + +// Responsive tables +// +// Wrap your tables in `.table-responsive` and we'll make them mobile friendly +// by enabling horizontal scrolling. Only applies <768px. Everything above that +// will display normally. + +.table-responsive { + @media screen and (max-width: @screen-xs-max) { + + // Special overrides for the bordered tables + > .table-bordered { + border: 0; + + // Nuke the appropriate borders so that the parent can handle them + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-right: 0; + border-left: initial; + } + > th:last-child, + > td:last-child { + border-left: 0; + border-right: initial; + } + } + } + + } + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/type-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/type-rtl.less new file mode 100644 index 0000000000..62cb748803 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/type-rtl.less @@ -0,0 +1,70 @@ +// +// RTL Typography +// -------------------------------------------------- + +// Flipped Alignment +.flip.text-left { text-align: right; } +.flip.text-right { text-align: left; } + +// List options + +// Unstyled keeps list items block level, just removes default browser padding and list-style +.list-unstyled { + padding-right: 0; + padding-left: initial; +} + +// Inline turns list items into inline-block +.list-inline { + .list-unstyled(); + margin-right: -5px; + margin-left: 0; +} + +dd { + margin-right: 0; // Undo browser default + margin-left: initial; +} + +// Horizontal description lists +// +// Defaults to being stacked without any of the below styles applied, until the +// grid breakpoint is reached (default of ~768px). + +.dl-horizontal { + + @media (min-width: @grid-float-breakpoint) { + dt { + float: right; + clear: right; + text-align: left; + } + dd { + margin-right: @component-offset-horizontal; + margin-left: 0; + } + } + @media (max-width: @grid-float-breakpoint) { + dt { + text-align: right; + } + } +} + +// Blockquotes +blockquote { + border-right: 5px solid @blockquote-border-color; + border-left: 0; +} + +// Opposite alignment of blockquote +// +// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0. +.blockquote-reverse, +blockquote.pull-left { + padding-left: 15px; + padding-right: 0; + border-left: 5px solid @blockquote-border-color; + border-right: 0; + text-align: left; +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/utilities-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/utilities-rtl.less new file mode 100644 index 0000000000..eaf8db421c --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/utilities-rtl.less @@ -0,0 +1,15 @@ +// +// Temporary RTL style to fix bugs rapidly. +// They will move to some place more appropriate later. +// -------------------------------------------------- + +.pull-right { + &.flip { + float: left !important; + } +} +.pull-left { + &.flip { + float: right !important; + } +} diff --git a/frontend/less/espo-rtl/bootstrap-rtl/variables-rtl.less b/frontend/less/espo-rtl/bootstrap-rtl/variables-rtl.less new file mode 100644 index 0000000000..13afd053b7 --- /dev/null +++ b/frontend/less/espo-rtl/bootstrap-rtl/variables-rtl.less @@ -0,0 +1,8 @@ +// +// RTL Variables +// -------------------------------------------------- + + +//== Media Objects on pull-left/pull-right + flip +//REMOVED @media-pull-margin: 10px; + diff --git a/frontend/less/espo-rtl/custom.less b/frontend/less/espo-rtl/custom.less new file mode 100644 index 0000000000..f2a80ee346 --- /dev/null +++ b/frontend/less/espo-rtl/custom.less @@ -0,0 +1,232 @@ + .dropdown-menu { + left: auto; + right: 0; +} + + .dropdown-menu-right { + left: 0; + right: auto; +} + +.dropdown-menu-left { + left: auto; + right: 0; +} + +.list .checkbox-dropdown { + margin-left: -10px; + margin-right: 0; +} + +.list-buttons-container > div { + float: right; + margin-left: @panel-padding; + margin-right: 0; +} + +.list-buttons-container > div.total-count { + margin-left: 0; + margin-right: 0; + float: left; + padding: 6px 0; +} + +li .preset .pull-right { + float: left !important; +} + +.preset > div { + padding-right: 0; + padding-left: 20px; +} + +ul.dropdown-menu > li.checkbox { + padding: 3px 20px 3px 0; +} + +.remove-filter.pull-right { + float: left !important; +} + +.modal-body > div > .list > table td:first-child, +.modal-body > div > .list > table th:first-child { + padding-right: @panel-padding; + padding-left: @table-cell-padding / 2; +} +.modal-body > div > .list > table td:last-child, +.modal-body > div > .list > table th:last-child { + padding-left: @panel-padding; + padding-right: @table-cell-padding / 2; +} + +#main > .list-container > .list { + margin-left: -@container-padding; + margin-right: -@container-padding; +} +#main > .list-container > .list > table td:first-child, +#main > .list-container > .list > table th:first-child { + padding-right: @panel-padding; + padding-left: @table-cell-padding / 2; +} +#main > .list-container > .list > table td:last-child, +#main > .list-container > .list > table th:last-child { + padding-left: @panel-padding; + padding-right: @table-cell-padding / 2; +} + +.panel-body .no-side-margin { + + > table td:first-child, + > table th:first-child { + padding-right: @panel-padding; + padding-left: @table-cell-padding / 2; + } + + > table td:last-child, + > table th:last-child { + padding-left: @panel-padding; + padding-right: @table-cell-padding / 2; + } +} + +.modal-footer .btn { + float: right; +} + +.detail-button-container > .pull-right, +.edit-button-container > .pull-right +{ + float: left !important; +} + +.header-buttons.pull-right { + float: left !important; +} + +.header-breadcrumbs > .pull-left { + float: right !important; +} + +.calendar-container .range-switch-group .btn { + direction: ltr; +} + +.calendar-container .button-container > div > div.pull-right { + float: left !important; +} + +.dropdown-menu > li > a > span.pull-right { + float: left !important; +} + +.panel > .panel-heading > .pull-right.btn-group { + float: left !important; + .dropdown-menu { + left: 0; + right: auto; + } +} + +.panel-heading > .btn-group { + right: 0; + margin-left: -11px; +} + +.panel > .panel-heading > .pull-right.dropdown { + float: left !important; + right: 0; + margin-left: -11px; + .dropdown-menu { + left: 0; + right: auto; + } +} + +.panel .panel-heading > a.pull-right { + float: left !important; +} + +.cell > a.pull-right { + float: left !important; +} + +.inline-save-link { + margin-left: 8px; +} + +.inline-cancel-link { + margin-left: 0; +} + +td.cell[data-name="buttons"] > .btn-group { + margin-right: -17px; +} + +.list-expanded > .list-group > .list-group-item > .pull-right { + float: left !important; +} + +.list-expanded > .list-group > .list-group-item > .pull-right > .list-row-buttons { + float: left !important; + margin-right: 0; + margin-left: -16px; +} + +.link-container > .list-group-item > .pull-right { + float: left !important; +} + +.link-container > .list-group-item > .pull-left > .pull-right { + float: left !important; +} + +.link-container > .list-group-item > .pull-left { + float: right !important; +} + +.field .link-container .list-group-item.link-with-role a { + margin-right: 14px; +} + +#global-search-panel { + left: 35px; + right: auto; +} + +#notifications-panel { + left: 0; + right: auto; + .panel .panel-heading .pull-right { + float: left !important; + } +} + +.page-header > div.row > div > .pull-right { + float: left !important; +} + +.grid-stack { + direction: ltr; +} + +.grid-stack > div { + direction: rtl; +} + +.dynamic-logic-expression-container { + .pull-right { + float: left !important; + } +} + +#fields-panel .cell .field { + .pull-right { + float: left !important; + } +} + +.gray-box { + .pull-right { + float: left !important; + } +} \ No newline at end of file diff --git a/frontend/less/espo-rtl/main.less b/frontend/less/espo-rtl/main.less new file mode 100644 index 0000000000..2621c0d596 --- /dev/null +++ b/frontend/less/espo-rtl/main.less @@ -0,0 +1,15 @@ +@import "../espo/bootstrap/bootstrap.less"; + +@import "bootstrap-rtl/bootstrap-rtl.less"; + +@import "../espo/variables.less"; +@import "variables.less"; + +@import "../espo/mixins.less"; +@import "../espo/misc.less"; +@import "../espo/layout.less"; +@import "../espo/custom.less"; + +@import "custom.less"; + +@import "bootstrap-rtl/utilities-rtl.less"; diff --git a/frontend/less/espo-rtl/variables.less b/frontend/less/espo-rtl/variables.less new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/less/espo-vertical/custom.less b/frontend/less/espo-vertical/custom.less index 45e8b4668b..700751be0b 100644 --- a/frontend/less/espo-vertical/custom.less +++ b/frontend/less/espo-vertical/custom.less @@ -12,7 +12,7 @@ } #global-search-input { - border: 1px solid @main-gray; + border: 1px solid @top-navbar-bg-color; font-size: 13px; width: 200px; } @@ -38,4 +38,5 @@ #global-search-panel { margin-top: -1px; } -} \ No newline at end of file +} + diff --git a/frontend/less/espo-vertical/layout.less b/frontend/less/espo-vertical/layout.less index 30b44bb549..00e27ead89 100644 --- a/frontend/less/espo-vertical/layout.less +++ b/frontend/less/espo-vertical/layout.less @@ -199,7 +199,7 @@ body > #header .navbar-brand span.home-icon { left: 0; height: @tob-bar-height; width: 100%; - background-color: @main-gray; + background-color: @top-navbar-bg-color; margin-left: @navbar-width; padding-right: @navbar-width; } diff --git a/frontend/less/espo-vertical/variables.less b/frontend/less/espo-vertical/variables.less index 6abbbaf284..4aace55c32 100644 --- a/frontend/less/espo-vertical/variables.less +++ b/frontend/less/espo-vertical/variables.less @@ -1,3 +1,4 @@ @navbar-width: 153px; @navbar-minimized-width: 40px; -@tob-bar-height: 30px; \ No newline at end of file +@tob-bar-height: 30px; +@top-navbar-bg-color: @main-gray; \ No newline at end of file diff --git a/frontend/less/espo/custom.less b/frontend/less/espo/custom.less index 8c1495627e..ec0c4ed510 100644 --- a/frontend/less/espo/custom.less +++ b/frontend/less/espo/custom.less @@ -98,6 +98,10 @@ label { min-height: 33px; } +.page-header > .row { + min-height: 33px; +} + .modal-header { background-color: @default-heading-bg-color; } @@ -446,7 +450,7 @@ select[multiple].input-sm { } .input-group-btn > select.form-control { - position: relative; + position: relative; display: inline-block; width: auto; vertical-align: middle; @@ -458,6 +462,10 @@ select[multiple].input-sm { margin-left: -1px; } +.input-group > .middle-element { + margin-left: 0 !important; +} + .input-group .form-control:focus { z-index: 3; } @@ -789,7 +797,7 @@ td.cell[data-name="buttons"] > .btn-group { } .panel { - border-width: 2px; + border-width: @panel-border-width; } .panel-heading > .btn-group > .btn { @@ -839,13 +847,13 @@ td.cell[data-name="buttons"] > .btn-group { .stick-sub { position: fixed; top: 0; - margin: 44px 0 0; + margin: 44px 0 0 -@container-padding; z-index: 4; } .stick-sub.button-container { background-color: @body-bg; - padding: 3px @container-padding*2 3px 0; + padding: 3px @container-padding 0 @container-padding; width: 100%; } @@ -959,7 +967,7 @@ body > footer > p a:visited { .record .middle > .panel:first-child { margin-top: 0; - border-top-width: 2px; + border-top-width: @panel-border-width; } .record .middle > .panel { @@ -1255,7 +1263,9 @@ h5 { width: 270px; } - +.inline-cancel-link { + margin-left: 8px; +} .dynamic-logic-expression-container { div.item-list { @@ -1288,6 +1298,18 @@ h5 { } } +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + margin-left: -1px; +} + +.input-group > .input-group-btn > .btn:hover, +.input-group > .input-group-btn > .btn:focus, +.input-group > .input-group-btn > .btn.active { + z-index: 3; +} + @media screen and (min-width: @screen-sm-min) { #global-search-panel { margin-top: 5px; diff --git a/frontend/less/espo/variables.less b/frontend/less/espo/variables.less index b83d6a6f79..27d274603b 100644 --- a/frontend/less/espo/variables.less +++ b/frontend/less/espo/variables.less @@ -121,3 +121,5 @@ @logo-height: 44px; @dashlet-unit-height: 155px; + +@panel-border-width: 2px; diff --git a/frontend/less/hazyblue/custom.less b/frontend/less/hazyblue/custom.less new file mode 100644 index 0000000000..2d51e3cec7 --- /dev/null +++ b/frontend/less/hazyblue/custom.less @@ -0,0 +1,103 @@ +.panel-heading { + border-bottom-width: 0; +} + +.panel-default.note-editor .panel-heading .btn-default { + background-color: @btn-default-bg; + border-color: @btn-default-border; +} + +.panel-default .panel-heading .btn-default { + background-color: @panel-default-heading-bg; + border-color: @panel-default-heading-bg; +} + +.panel-title { + font-size: 15px; + line-height: 16px; +} + +.modal-content { + background-color: @white-color; +} + +.modal-content > .modal-body { + background-color: @body-bg; +} + +.modal-body > .list-group { + background-color: @white-color; +} + +.list-container > .list { + background-color: @white-color; +} + +.modal-footer { + margin-top: 0; +} + +.panel-heading > .btn-group { + top: -5px; + right: -10px; +} + +table.table { + background-color: @white-color; +} + +.record .middle > .panel:first-child { + border-top-width: 1px; +} + +.record .middle > .panel { + border-top-width: 1px; +} + +.dashlet-body .list-container > .list, +.panel-body .list-container > .list { + box-shadow: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; +} + +.list-container > .list, +.panel, +.dashlet-container { + -webkit-box-shadow: 3px 3px 4px rgba(0,0,0,0.13); + -moz-box-shadow: 3px 3px 4px rgba(0,0,0,0.13); + box-shadow: 3px 3px 4px rgba(0,0,0,0.13); +} + +@media (min-width: 768px) { + .modal-dialog > .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0,0,0,0.5); + -moz-box-shadow: 0 5px 15px -3px rgba(0,0,0,0.5); + box-shadow: 0 5px 15px rgba(0,0,0,0.5); + } +} + +.panel.sticked { + border-top-width: 1px; +} + +.list-container .list-buttons-container { + margin-bottom: 10px; +} + +.modal-header { + background-color: @white-color; +} + +.calendar-container > .calendar, +.calendar-container > .timeline { + background-color: @white-color; +} + +.field .list-group { + background-color: @white-color; +} + +.field .grid-stack-item-content { + border: 1px solid @default-border-color; +} \ No newline at end of file diff --git a/frontend/less/hazyblue/main.less b/frontend/less/hazyblue/main.less new file mode 100644 index 0000000000..d762432b54 --- /dev/null +++ b/frontend/less/hazyblue/main.less @@ -0,0 +1,17 @@ +@import "../espo/bootstrap/bootstrap.less"; + +@import "../espo/variables.less"; +@import "../espo-vertical/variables.less"; + +@import "../espo/mixins.less"; + +@import "../espo/misc.less"; +@import "../espo-vertical/layout.less"; +@import "../espo/custom.less"; +@import "../espo-vertical/custom.less"; + +@import "variables.less"; + +@import "custom.less"; + +@import "../espo/bootstrap/utilities.less"; diff --git a/frontend/less/hazyblue/variables.less b/frontend/less/hazyblue/variables.less new file mode 100644 index 0000000000..300bb21fdf --- /dev/null +++ b/frontend/less/hazyblue/variables.less @@ -0,0 +1,17 @@ +@navbar-inverse-bg: #546E7A; +@body-bg: #ececec; +@top-navbar-bg-color: @body-bg; + +@white-color: #FFF; + +@panel-default-heading-bg: @white-color; + +@panel-border-width: 0; + +@panel-default-border: #dcdcdc; + +@btn-default-bg: #f7f7f7; +@btn-default-border: #cccccc; + +@brand-success: #85b75f; +@brand-primary: #537898; \ No newline at end of file