From 93a7c9f91e237554ad34aac6c5aaa7612fe96fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Wed, 30 May 2018 16:03:08 +0200 Subject: [PATCH 1/3] Allow to define RTL languages so the content can be mirrored --- app/coffee/app.coffee | 6 +++++- app/coffee/modules/common.coffee | 10 +++++++--- app/index.jade | 4 ++-- app/locales/taiga/locale-en.json | 1 - app/styles/core/elements.scss | 2 ++ conf/conf.example.json | 3 ++- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 652f1cf7..8443c039 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -753,7 +753,7 @@ i18nInit = (lang, $translate) -> init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $navUrls, appMetaService, - loaderService, navigationBarService, errorHandlingService, lightboxService) -> + loaderService, navigationBarService, errorHandlingService, lightboxService, $tgConfig) -> $log.debug("Initialize application") $rootscope.$on '$translatePartialLoaderStructureChanged', () -> @@ -782,6 +782,9 @@ init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $na $rootscope.$on "$translateChangeEnd", (e, ctx) -> lang = ctx.language i18nInit(lang, $translate) + # RTL + rtlLanguages = $tgConfig.get("rtlLanguages", []) + $rootscope.isRTL = rtlLanguages.indexOf(lang) > -1 # bluebird Promise.setScheduler (cb) -> @@ -930,5 +933,6 @@ module.run([ "tgNavigationBarService", "tgErrorHandlingService", "lightboxService", + "$tgConfig", init ]) diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index d9e42386..4ca84b92 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -29,9 +29,13 @@ module = angular.module("taigaCommon", []) ############################################################################# ## Default datepicker config ############################################################################# -DataPickerConfig = ($translate) -> +DataPickerConfig = ($translate, $config, $auth) -> return { get: () -> + user = $auth.getUser() + lang = user.lang || $translate.preferredLanguage() + rtlLanguages = $config.get("rtlLanguages", []) + isRTL = rtlLanguages.indexOf(lang) > -1 return { i18n: { previousMonth: $translate.instant("COMMON.PICKERDATE.PREV_MONTH"), @@ -69,13 +73,13 @@ DataPickerConfig = ($translate) -> $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.SAT") ] }, - isRTL: $translate.instant("COMMON.PICKERDATE.IS_RTL") == "true", + isRTL: isRTL, firstDay: parseInt($translate.instant("COMMON.PICKERDATE.FIRST_DAY_OF_WEEK"), 10), format: $translate.instant("COMMON.PICKERDATE.FORMAT") } } -module.factory("tgDatePickerConfigService", ["$translate", DataPickerConfig]) +module.factory("tgDatePickerConfigService", ["$translate", "$tgConfig", "$tgAuth", DataPickerConfig]) ############################################################################# ## Get the selected text diff --git a/app/index.jade b/app/index.jade index 438ba307..e0b37e63 100644 --- a/app/index.jade +++ b/app/index.jade @@ -1,5 +1,5 @@ doctype html -html(lang="en") +html(lang="en", ng-attr-dir="{{ isRTL ? 'rtl' : 'ltr' }}") head meta(charset="utf-8") meta(http-equiv="content-type", content="text/html; charset=utf-8") @@ -18,7 +18,7 @@ html(lang="en") script(type='text/javascript'). window.prerenderReady = false; - body(tg-main) + body(tg-main, ng-class="{'rtl': isRTL}") div(tg-navigation-bar, ng-if="!errorHandling.showingError") div(ng-if="!errorHandling.showingError") div.master(ng-view) diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index 4aa9250d..6af3550e 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -79,7 +79,6 @@ }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", - "IS_RTL": "false", "FIRST_DAY_OF_WEEK": "1", "PREV_MONTH": "Previous Month", "NEXT_MONTH": "Next Month", diff --git a/app/styles/core/elements.scss b/app/styles/core/elements.scss index a46902e2..0d606072 100644 --- a/app/styles/core/elements.scss +++ b/app/styles/core/elements.scss @@ -51,6 +51,8 @@ svg { //Datepicker .pika-single { // scss-lint:disable ImportantRule + min-width: 240px; + width: auto; z-index: 999999; .pika-title { color: $grayer; diff --git a/conf/conf.example.json b/conf/conf.example.json index b2a8b8a9..ee0cc0c1 100644 --- a/conf/conf.example.json +++ b/conf/conf.example.json @@ -19,5 +19,6 @@ "contribPlugins": [], "tribeHost": null, "importers": [], - "gravatar": true + "gravatar": true, + "rtlLanguages": ["fa"] } From 9edf58c6c82cfcaadf5670b837c1c09077641376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Fri, 8 Jun 2018 13:52:30 +0200 Subject: [PATCH 2/3] RTL styles --- app/modules/components/filter/filter.jade | 8 +- app/modules/components/filter/filter.scss | 3 + .../tags/tag-line-common/tag-line-common.jade | 2 +- app/styles/layout/rtl.scss | 749 ++++++++++++++++++ app/styles/layout/ticket-detail.scss | 4 + 5 files changed, 761 insertions(+), 5 deletions(-) create mode 100644 app/styles/layout/rtl.scss diff --git a/app/modules/components/filter/filter.jade b/app/modules/components/filter/filter.jade index 2cd04fa7..590d65b8 100644 --- a/app/modules/components/filter/filter.jade +++ b/app/modules/components/filter/filter.jade @@ -19,13 +19,13 @@ form(name="vm.filtersForm") .filters-applied .single-filter.ng-animate-disabled(ng-repeat="it in vm.selectedFilters track by it.key") span.name( - ng-attr-style="{{it.color ? 'border-left: 3px solid ' + it.color: ''}}" + ng-attr-style="{{it.color ? 'border-color: ' + it.color: ''}}" ng-if="it.dataType === 'tags'" ng-bind-html="it.name | emojify" ) span.name( ng-if="it.dataType !== 'tags'" - ng-attr-style="{{it.color ? 'border-left: 3px solid ' + it.color: ''}}" + ng-attr-style="{{it.color ? 'border-color: ' + it.color: ''}}" ) {{it.name}} a.remove-filter.e2e-remove-filter( ng-click="vm.unselectFilter(it)" @@ -87,12 +87,12 @@ form(name="vm.filtersForm") ) span.name( ng-if="filter.dataType === 'tags'", - ng-attr-style="{{it.color ? 'border-left: 3px solid ' + it.color: ''}}" + ng-attr-style="{{it.color ? 'border-color: ' + it.color: ''}}" ng-bind-html="it.name | emojify" ) span.name( ng-if="filter.dataType !== 'tags'", - ng-attr-style="{{it.color ? 'border-left: 3px solid ' + it.color: ''}}" + ng-attr-style="{{it.color ? 'border-color: ' + it.color: ''}}" ) {{it.name}} span.number.e2e-filter-count(ng-if="it.count > 0") {{it.count}} diff --git a/app/modules/components/filter/filter.scss b/app/modules/components/filter/filter.scss index 1bcd1959..99220da0 100644 --- a/app/modules/components/filter/filter.scss +++ b/app/modules/components/filter/filter.scss @@ -126,6 +126,9 @@ tg-filter { } .name { @include ellipsis(100%); + border-color: transparent; + border-style: solid; + border-width: 0 0 0 3px; display: block; width: 100%; img { diff --git a/app/modules/components/tags/tag-line-common/tag-line-common.jade b/app/modules/components/tags/tag-line-common/tag-line-common.jade index e5c44ae3..a08ae452 100644 --- a/app/modules/components/tags/tag-line-common/tag-line-common.jade +++ b/app/modules/components/tags/tag-line-common/tag-line-common.jade @@ -2,7 +2,7 @@ .tag( ng-if="tag[1] && !vm.disableColorSelection" ng-repeat="tag in vm.tags" - ng-style="{'border-left': '.3rem solid' + tag[1]}" + ng-style="{'border-color': tag[1]}" ) tg-tag( tag="tag" diff --git a/app/styles/layout/rtl.scss b/app/styles/layout/rtl.scss new file mode 100644 index 00000000..be607874 --- /dev/null +++ b/app/styles/layout/rtl.scss @@ -0,0 +1,749 @@ +.rtl { + .navbar .nav-right { + margin: 0; + .user-avatar { + padding-left: 0; + padding-right: 2em; + text-align: left; + } + img { + margin-left: 0; + margin-right: .5rem; + } + } + .admin-menu li a { + padding: 1rem 1rem 1rem 0; + } + + h1 span { + margin-left: .5rem; + margin-right: 0; + } + + blockquote { + border-left: 0; + border-right: 5px solid $mass-white; + } + + .tag { + border-color: transparent; + border-radius: 5px 0 0 5px; + border-width: 0 3px 0 0; + margin: 0 0 .5rem .5rem; + .icon-close { + margin-left: 0; + margin-right: .25rem; + } + } + + .home-wrapper .working-on-container { + margin-left: 1rem; + margin-right: 0; + } + + .home-project .project-card-logo { + margin-left: .5rem; + margin-right: 0; + } + + .home-project .project-card-statistics svg { + margin-left: .25rem; + margin-right: 0; + } + + .contact-team-large .icon-mail { + margin-left: .5rem; + margin-right: 0; + } + + .user-profile .project-details-image { + margin-left: 2rem; + margin-right: 0; + } + + .single-project .project-logo { + margin-left: 1rem; + margin-right: 0; + } + + .profile-timeline .activity-item .profile-contact-picture, + .profile-timeline .activity-item .profile-member-picture { + margin-left: 1rem; + margin-right: 0; + } + + .profile-timeline .activity-item { + padding: 1rem 0 1rem .5rem; + .activity-date { + left: .5rem; + right: auto; + } + .activity-info { + margin-left: 130px; + margin-right: 0; + } + blockquote { + margin-left: 0; + margin-right: calc(35px + 1rem); + } + } + + .profile-timeline .single-attachment .icon { + margin-left: .5rem; + margin-right: 0; + } + + .project-data .involved-team li { + margin-left: .13rem; + margin-right: 0; + } + + .project-details-form-data .actions .delete-account { + text-align: left; + } + + .project-data .timeline { + margin-left: 1rem; + margin-right: 0; + } + + .track-icon { + margin-left: .5rem; + margin-right: 0; + } + + .watch-options-arrow { + margin-left: 0; + margin-right: auto; + } + + .ticket-estimation .ticket-role-points .icon-arrow-down { + margin-left: 0; + margin-right: .25rem; + } + + .ticket-watch { + .ticket-watch-button { + margin-left: .25rem; + margin-right: 0; + } + svg { + margin-left: .25rem; + margin-right: 0; + } + } + + .related-tasks-body { + .task-assignedto .icon { + left: .5rem; + right: 0; + } + .avatar figcaption { + margin-left: 0; + margin-right: .5rem; + } + .task-name { + margin-left: 1rem; + margin-right: 0; + span { + margin-left: .25rem; + margin-right: 0; + } + } + } + + tg-filter .search-action { + left: .7rem; + right: auto; + } + + .issues-table .issue-field, + .issues-table .assigned-field, + .issues-table .created-field, + .issues-table .assigned-field { + text-align: right; + } + + .issues-table .issue-field .icon, + .issues-table .assigned-field .icon, + .issues-table .created-field .icon, + .issues-table .assigned-field .icon { + margin-left: 0; + margin-right: .25rem; + } + + .icon-arrow-left, + .icon-arrow-right { + transform: scaleX(-1); + } + + .issues-table { + .pop-status { + left: auto; + right: 0; + } + .icon-upvote { + margin-left: .25rem; + margin-right: 0; + } + .subject { + padding-left: 1rem; + padding-right: 0; + a { + text-align: right; + } + } + .issue-assignedto .icon { + left: 0; + right: auto; + } + .avatar figcaption { + margin-left: 0; + margin-right: .5rem; + } + } + + .single-filter { + padding-left: .5rem; + padding-right: 0; + .number { + left: 0; + right: auto; + } + .name { + border-color: transparent; + border-style: solid; + border-width: 0 3px 0 0; + } + } + + .discover-header .search-button { + left: 1rem; + right: auto; + } + + .highlighted .header svg { + margin-left: 0; + margin-right: .5rem; + &.icon-activity, + &.icon-like { + margin-left: .5rem; + margin-right: 0; + } + } + + .highlighted tg-most-liked { + margin-left: 8%; + margin-right: 0; + } + + .highlighted-project { + .statistic { + margin-left: .5rem; + margin-right: 0; + } + .project-statistics svg { + margin-left: .25rem; + margin-right: 0; + } + + .project-logo { + margin-left: 1rem; + margin-right: 0; + } + } + + .featured-project { + .project-card-logo { + margin-left: .5rem; + margin-right: 0; + } + .project-card-statistics svg { + margin-left: .25rem; + margin-right: 0; + } + } + + .project-list-wrapper { + .project-list { + margin-left: 2rem; + margin-right: 0; + } + .list-itemtype-project .list-itemtype-project-image { + margin-left: 1rem; + margin-right: 0; + } + } + + .create-project-selector-question { + left: 1.5rem; + right: auto; + } + + .create-project-title-wrapper .icon { + margin-left: .5rem; + margin-right: 0; + } + + .create-project-privacity label .icon { + margin-left: .25rem; + margin-right: 0; + } + + .create-project-action-submit { + margin-left: 0; + margin-right: 1rem; + } + + .summary-progress-bar { + margin-left: 10px; + margin-right: 0; + } + + .empty-burndown svg { + margin-left: 2rem; + margin-right: 0; + } + + .backlog-menu .button-bulk { + margin-left: 0; + margin-right: .2rem; + } + + .ticket-header .detail-status { + margin-left: 0; + margin-right: .25rem; + } + + .ticket-status { + .level-name { + float: left; + } + .level { + margin-left: .5rem; + margin-right: 0; + } + } + + .ticket-data-container .icon { + margin-left: 0; + margin-right: .25rem; + } + + .ticket-assigned-to { + .assigned-to { + margin-left: 0; + margin-right: .5rem; + } + } + + .user-list-avatar { + margin-left: .25rem; + margin-right: 0; + } + + .user-list-name { + margin-left: 0; + margin-right: .5rem; + } + + .assigned-to-list .user-list-multiple .remove-assigned-to, + .assigned-to-list .user-list-single .remove-assigned-to, + .ticket-watchers .delete-watcher, + .ticket-assigned-to .remove-user, + .ticket-assigned-users .remove-user { + left: .5rem; + right: auto; + } + + .lightbox .close { + left: 3rem; + right: auto; + } + + .comment .comment-avatar, + .activity .activity-avatar { + margin-left: 1.5rem; + margin-right: 0; + } + + .comment .comment-creator { + margin-left: .5rem; + margin-right: 0; + } + + tg-wysiwyg .tools { + padding-left: 0; + padding-right: 1rem; + } + + .add-tag-button .icon-add { + margin: .5rem 0 0 .25rem; + } + + .add-tag-input .save { + margin: .5rem .5rem 0 0; + } + + .issue-nav { + left: 1rem; + right: auto; + } + + .upvote-btn { + margin-left: .3rem; + margin-right: 0; + } + + .taskboard-table-header .taskboard-table-inner { + margin-left: 1rem; + } + .taskboard-table-header .task-colum-name { + margin: 0 0 0 5px; + } + + .kanban-table-header { + margin-left: -3.7rem; + .task-colum-name { + margin: 0 0 0 5px; + } + } + + .taskboard-table-body .task-column, + .kanban-table-body .task-column { + margin: 0 0 0 5px; + &:last-child { + margin-left: 0; + margin-right: initial; + } + } + + .backlog-table-body { + .votes svg { + margin-left: .25rem; + margin-right: 0; + } + .user-story-name a { + text-align: right; + } + } + + .backlog-table-header .backlog-table-title { + padding-left: 1rem; + padding-right: 0; + } + + .backlog-table-header .backlog-table-title .status, + .backlog-table-header .row .status, + .backlog-table-body .backlog-table-title .status, + .backlog-table-body .row .status { + flex-basis: 150px; + text-align: right; + } + + .backlog-table-header .backlog-table-title .user-stories, + .backlog-table-header .row .user-stories, + .backlog-table-body .backlog-table-title .user-stories, + .backlog-table-body .row .user-stories { + text-align: right; + } + + .backlog-table-header .status .icon, + .backlog-table-header .points .icon, + .backlog-table-body .status .icon, + .backlog-table-body .points .icon { + margin-left: 0; + margin-right: .2rem; + } + + .sprints { + .sprint-table { + .column-us { + text-align: right; + } + .column-points { + text-align: left; + } + } + .sprint .edit-sprint { + left: 0; + margin-left: .5rem; + margin-right: 0; + right: auto; + } + } + + .epic-row .progress-bar, + .epic-row .progress-status { + left: auto; + right: 0; + } + + .ticket-created-by { + .user-avatar { + margin-left: 0; + margin-right: .5rem; + } + .created-by .created-date { + margin-left: 0; + margin-right: .5rem; + } + .created-by .created-title, + .created-by .created-date { + text-align: left; + } + } + + tg-wysiwyg .medium-editor-placeholder, + tg-wysiwyg .markdown-editor-placeholder { + padding-left: 0; + padding-right: 1rem; + text-align: right; + } + + .attachments-header { + button { + margin-left: .2rem; + margin-right: 0; + } + label { + margin-left: 0; + margin-right: .25rem; + } + } + + .attachment-list { + .attachment-comments, + .editable-attachment-comment { + margin-left: .5rem; + margin-right: 0; + } + .editable-attachment-deprecated input { + margin-left: .2rem; + margin-right: 0; + } + } + + .more-attachments .more-attachments-num { + margin-left: 0; + margin-right: .5rem; + } + + .single-attachment .attachment-name { + padding-left: 1rem; + padding-right: 0; + svg { + margin-left: .25rem; + margin-right: 0; + } + } + + .wiki-nav .add-button svg { + margin-left: .5rem; + margin-right: 0; + } + + .wiki-pages-table { + .title-field, + .created-field, + .modified-field, + .last-modifier-field, + .creator-field { + text-align: right; + } + } + + .wiki-summary div { + margin-left: 1.25rem; + margin-right: 0; + } + + .summary .number { + margin-left: .3rem; + margin-right: 0; + } + + .table-team { + .avatar .avatar-data { + margin-left: 0; + margin-right: 1rem; + text-align: right; + } + .leave-project .icon { + margin-left: .2rem; + margin-right: 0; + } + } + + .belong-to-epic-text-wrapper { + margin-left: 1rem; + margin-right: 0; + } + + .epics-table-options-wrapper { + left: .5rem; + right: auto; + } + + .epics-table-dropdown { + left: 0; + right: auto; + } + + .story-row .icon-upvote, + .epic-row .icon-upvote { + margin-left: .25rem; + margin-right: 0; + } + + .story-row { + margin-left: 0; + margin-right: 4rem; + } + + .epic-row .icon-arrow-down { + margin-left: 0; + margin-right: .1rem; + } + + .epic-header-container .color-selector { + margin-left: .5rem; + margin-right: 0; + } + + .related-userstories-header .related-userstories-title { + margin-left: 0; + margin-right: 1rem; + } + + tg-related-userstory-row { + .userstory-name { + margin-left: 1rem; + margin-right: 0; + span { + margin-left: 0; + margin-right: .25rem; + } + } + .avatar figcaption { + margin-left: 0; + margin-right: .5rem; + } + } + + .card-owner-actions .icon { + margin-left: .25rem; + margin-right: 0; + } + + .card-owner { + img { + margin-left: .5rem; + margin-right: 0; + } + .card-owner-avatar img { + margin-left: .45rem; + margin-right: 0; + } + } + + .card-statistics { + .statistic { + margin-left: .5rem; + margin-right: .5rem; + } + .icon { + margin-left: .2rem; + margin-right: 0; + } + } + + .lightbox-create-related-user-stories { + .related-with-selector .related-with-selector-single:first-child { + margin-left: .5rem; + margin-right: 0; + } + .new-user-story-options { + margin-left: 0; + margin-right: auto; + } + } + + .lightbox-generic-form .settings fieldset { + margin-left: .5rem; + margin-right: 0; + } + + .ticket-estimation .popover { + left: auto; + right: .5rem; + &:after { + left: auto; + right: 10px; + } + } + + .profile { + .timeline-wrapper { + margin-left: 3.5rem; + margin-right: 0; + } + + .profile-bar { + margin-left: 1rem; + margin-right: 0; + } + } + + .profile-content-tabs .icon { + margin-left: .5rem; + margin-right: 0; + } + .profile-sidebar h4 .icon { + margin-left: .3rem; + margin-right: auto; + } + + .profile-filter .searchbox input { + margin-left: 1rem; + margin-right: 0; + } + .profile-filter .searchbox .icon-search { + margin-left: .5rem; + margin-right: 0; + } + + .list-itemtype-ticket .list-itemtype-track .list-itemtype-track-likers, + .list-itemtype-project .list-itemtype-track .list-itemtype-track-likers, + .list-itemtype-ticket .list-itemtype-avatar, + .list-itemtype-project .list-itemtype-project-image { + margin-left: .5rem; + margin-right: 0; + } + + .list-itemtype-ticket .list-itemtype-track-likers .icon, + .list-itemtype-ticket .list-itemtype-track-watchers .icon, + .list-itemtype-project .list-itemtype-track-likers .icon, + .list-itemtype-project .list-itemtype-track-watchers .icon { + margin-left: .25rem; + margin-right: 0; + } + + .list-itemtype-ticket.blocked-project .icon-blocked-project { + margin-left: 0; + margin-right: .25rem; + } + + .list-itemtype-ticket .list-itemtype-ticket-data { + margin-left: 1rem; + margin-right: 0; + } + + .list-itemtype-user .list-itemtype-avatar { + margin-left: .75rem; + margin-right: 0; + } + +} + + diff --git a/app/styles/layout/ticket-detail.scss b/app/styles/layout/ticket-detail.scss index 8e0efc4f..6bfcbced 100644 --- a/app/styles/layout/ticket-detail.scss +++ b/app/styles/layout/ticket-detail.scss @@ -30,6 +30,10 @@ @include breakpoint(laptop) { order: 2; } + .tag { + border-color: transparent; + border-style: solid; + } } } From 97c909dcd17eaf5b1ce964f92e94e5ef95fe7397 Mon Sep 17 00:00:00 2001 From: Miguel Gonzalez Date: Tue, 12 Jun 2018 17:52:16 +0200 Subject: [PATCH 3/3] Fix minor style issues --- app/styles/layout/rtl.scss | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/styles/layout/rtl.scss b/app/styles/layout/rtl.scss index be607874..5c341849 100644 --- a/app/styles/layout/rtl.scss +++ b/app/styles/layout/rtl.scss @@ -4,7 +4,7 @@ .user-avatar { padding-left: 0; padding-right: 2em; - text-align: left; + text-align: left; } img { margin-left: 0; @@ -161,7 +161,7 @@ .issues-table .assigned-field, .issues-table .created-field, .issues-table .assigned-field { - text-align: right; + text-align: right; } .issues-table .issue-field .icon, @@ -343,7 +343,7 @@ } .user-list-name { - margin-left: 0; + margin-left: 0; margin-right: .5rem; } @@ -651,7 +651,7 @@ .statistic { margin-left: .5rem; margin-right: .5rem; - } + } .icon { margin-left: .2rem; margin-right: 0; @@ -677,7 +677,7 @@ .ticket-estimation .popover { left: auto; right: .5rem; - &:after { + &::after { left: auto; right: 10px; } @@ -741,7 +741,7 @@ .list-itemtype-user .list-itemtype-avatar { margin-left: .75rem; - margin-right: 0; + margin-right: 0; } }