Commit c9e0fbd34222397332aa83d66ed06550e7b27731
1 parent
8f52051e
Refactor the 'ProfileToolbarComponent' to a new concept using 'ConfigBarComponen…
…t' aligned to right of screen
Showing
13 changed files
with
229 additions
and
60 deletions
Show diff stats
bower.json
... | ... | @@ -39,7 +39,8 @@ |
39 | 39 | "angular-click-outside": "^2.7.1", |
40 | 40 | "ng-ckeditor": "^0.2.1", |
41 | 41 | "angular-bootstrap-toggle-switch": "^0.5.6", |
42 | - "angular-tag-cloud": "^0.3.0" | |
42 | + "angular-tag-cloud": "^0.3.0", | |
43 | + "angular-ui-switch": "^0.1.1" | |
43 | 44 | }, |
44 | 45 | "devDependencies": { |
45 | 46 | "angular-mocks": "~1.5.0" | ... | ... |
src/app/admin/layout-edit/designModeToggler.component.spec.ts
1 | 1 | import {ComponentTestHelper, createClass} from '../../../spec/component-test-helper'; |
2 | +import {INgForwardJQuery} from 'ng-forward/cjs/util/jqlite-extensions'; | |
2 | 3 | import * as helpers from '../../../spec/helpers'; |
3 | 4 | import {DesignModeTogglerComponent} from './designModeToggler.component'; |
4 | 5 | import {DesignModeService} from './designMode.service'; |
5 | 6 | import {INoosferoLocalStorage} from "./../../shared/models/interfaces"; |
6 | 7 | |
7 | 8 | describe('DesignModeToggler Component', () => { |
8 | - const htmlTemplate: string = '<noosfero-design-toggler></noosfero-design-toggler>'; | |
9 | + const htmlTemplate: string = '<design-toggler></design-toggler>'; | |
9 | 10 | |
10 | 11 | let helper: ComponentTestHelper<DesignModeTogglerComponent>; |
11 | 12 | beforeEach(() => { |
12 | 13 | angular.mock.module('templates'); |
13 | 14 | angular.mock.module('ngSanitize'); |
14 | - angular.mock.module('toggle-switch'); | |
15 | + angular.mock.module('uiSwitch'); | |
15 | 16 | }); |
16 | 17 | |
17 | 18 | let designModeService: DesignModeService; |
... | ... | @@ -30,12 +31,12 @@ describe('DesignModeToggler Component', () => { |
30 | 31 | }); |
31 | 32 | |
32 | 33 | it('changes css classes representing the switch is on or off', () => { |
33 | - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-off')).toBeTruthy(); | |
34 | - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-on')).toBeFalsy(); | |
34 | + let switchEl: INgForwardJQuery = helper.debugElement.query('span.switch'); | |
35 | + | |
36 | + expect(switchEl.hasClass('checked')).toBeFalsy(); | |
35 | 37 | helper.component.inDesignMode = true; |
36 | 38 | helper.detectChanges(); |
37 | - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-on')).toBeTruthy(); | |
38 | - expect(helper.debugElement.query('div.switch-animate').hasClass('switch-off')).toBeFalsy(); | |
39 | + expect(switchEl.hasClass('checked')).toBeTruthy(); | |
39 | 40 | }); |
40 | 41 | |
41 | 42 | it('emits event with value "true" when changing inDesignMode to On', (done) => { |
... | ... | @@ -60,4 +61,4 @@ describe('DesignModeToggler Component', () => { |
60 | 61 | helper.component.inDesignMode = false; |
61 | 62 | helper.detectChanges(); |
62 | 63 | }); |
63 | -}); | |
64 | 64 | \ No newline at end of file |
65 | +}); | ... | ... |
src/app/admin/layout-edit/designModeToggler.component.ts
... | ... | @@ -3,17 +3,12 @@ import {DesignModeService} from './designMode.service'; |
3 | 3 | import {AuthService, AuthEvents} from '../../login'; |
4 | 4 | |
5 | 5 | @Component({ |
6 | - selector: 'noosfero-design-toggler', | |
6 | + selector: 'design-toggler', | |
7 | 7 | templateUrl: 'app/admin/layout-edit/designModeToggler.html' |
8 | 8 | }) |
9 | 9 | @Inject(DesignModeService, AuthService, '$sce') |
10 | 10 | export class DesignModeTogglerComponent { |
11 | 11 | |
12 | - @Input() iconClass: string = ''; | |
13 | - @Input() knobLabel: string = ''; | |
14 | - @Input() offLabel: string = ''; | |
15 | - @Input() onLabel: string = ''; | |
16 | - | |
17 | 12 | private _inDesignMode: boolean = false; |
18 | 13 | |
19 | 14 | constructor(private designModeService: DesignModeService, private authService: AuthService, private $sce: ng.ISCEService) { |
... | ... | @@ -22,19 +17,6 @@ export class DesignModeTogglerComponent { |
22 | 17 | }); |
23 | 18 | } |
24 | 19 | |
25 | - get icon(): string { | |
26 | - if (this.iconClass && this.iconClass.trim().length > 0) { | |
27 | - return '<i class=\'design-toggle-icon ' + this.iconClass + '\'></i>'; | |
28 | - } | |
29 | - else { | |
30 | - return ''; | |
31 | - } | |
32 | - } | |
33 | - | |
34 | - getKnobLabel(): string { | |
35 | - return this.$sce.trustAsHtml(this.icon + this.knobLabel); | |
36 | - } | |
37 | - | |
38 | 20 | get inDesignMode(): boolean { |
39 | 21 | return this.designModeService.isInDesignMode(); |
40 | 22 | }; | ... | ... |
src/app/admin/layout-edit/designModeToggler.html
1 | -<toggle-switch | |
2 | - html="true" | |
3 | - ng-model="ctrl.inDesignMode" | |
4 | - on-label="{{ctrl.onLabel}}" | |
5 | - off-label="{{ctrl.offLabel}}" | |
6 | - class="switch-small" | |
7 | - knob-label="{{ ctrl.getKnobLabel() }}"> | |
8 | -</toggle-switch> | |
9 | 1 | \ No newline at end of file |
2 | +<switch id="enabled" name="enabled" ng-model="ctrl.inDesignMode" on="ON" off="OFF" class="green"></switch> | ... | ... |
src/app/admin/layout-edit/designModeToggler.scss
1 | -ul.nav > li.toggler-container { | |
2 | - position: relative; | |
3 | - padding-top: 12px; | |
4 | -} | |
1 | +$off-text: #949494; | |
2 | +$off-color: #EFEFEF; | |
3 | +$blue-color: #36B4F6; | |
4 | +$red-color: #DF3B3A; | |
5 | 5 | |
6 | 6 | body.noosfero-design-on { |
7 | 7 | |
... | ... | @@ -10,14 +10,46 @@ body.noosfero-design-on { |
10 | 10 | } |
11 | 11 | } |
12 | 12 | |
13 | +.switch { | |
14 | + @include not-select(); | |
15 | + background-color: $off-color; | |
13 | 16 | |
17 | + &[on][off] { | |
18 | + width: 60px; | |
19 | + } | |
14 | 20 | |
15 | -noosfero-design-toggler .ats-switch .knob i { | |
16 | - color: #999999; | |
17 | -} | |
21 | + &:focus { | |
22 | + outline: none; | |
23 | + } | |
24 | + | |
25 | + &.checked small { | |
26 | + left: initial; | |
27 | + right: 0px; | |
28 | + } | |
29 | + | |
30 | + &.blue.checked { | |
31 | + background: $blue-color; | |
32 | + border-color: $blue-color; | |
33 | + } | |
18 | 34 | |
35 | + &.red.checked { | |
36 | + background: $red-color; | |
37 | + border-color: $red-color; | |
38 | + } | |
19 | 39 | |
20 | -.design-toggle-icon { | |
21 | - margin-left: 3px; | |
22 | - margin-right: 3px; | |
23 | -} | |
24 | 40 | \ No newline at end of file |
41 | + %switch-label { | |
42 | + font-weight: bold; | |
43 | + } | |
44 | + | |
45 | + .on { | |
46 | + @extend %switch-label; | |
47 | + } | |
48 | + | |
49 | + .off { | |
50 | + @extend %switch-label; | |
51 | + right: 2px; | |
52 | + top: 25%; | |
53 | + color: $off-text; | |
54 | + text-align: center; | |
55 | + } | |
56 | +} | ... | ... |
src/app/layout/scss/_mixins.scss
... | ... | @@ -4,6 +4,12 @@ |
4 | 4 | background-clip: padding-box; /* stops bg color from leaking outside the border: */ |
5 | 5 | } |
6 | 6 | |
7 | +@mixin box-shadow($args...) { | |
8 | + -webkit-box-shadow: $args; | |
9 | + -moz-box-shadow: $args; | |
10 | + box-shadow: $args; | |
11 | +} | |
12 | + | |
7 | 13 | @mixin checkbox-mark($width, $height, $top, $left, $bg, $border, $content: "", $cursor: pointer, $position: absolute) { |
8 | 14 | width: $width; |
9 | 15 | height: $height; |
... | ... | @@ -49,6 +55,16 @@ |
49 | 55 | } |
50 | 56 | } |
51 | 57 | |
58 | +@mixin not-select() { | |
59 | + -webkit-touch-callout: none; /* iOS Safari */ | |
60 | + -webkit-user-select: none; /* Chrome/Safari/Opera */ | |
61 | + -khtml-user-select: none; /* Konqueror */ | |
62 | + -moz-user-select: none; /* Firefox */ | |
63 | + -ms-user-select: none; /* Internet Explorer/Edge */ | |
64 | + user-select: none; /* Non-prefixed version, currently | |
65 | + not supported by any browser */ | |
66 | +} | |
67 | + | |
52 | 68 | @mixin keyframes($animation-name) { |
53 | 69 | @-webkit-keyframes #{$animation-name} { |
54 | 70 | @content; | ... | ... |
src/app/main/main.component.ts
... | ... | @@ -115,7 +115,7 @@ export class EnvironmentContent { |
115 | 115 | "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid", |
116 | 116 | "angular-timeline", "duScroll", "oitozero.ngSweetAlert", |
117 | 117 | "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad", |
118 | - "angular-click-outside", "toggle-switch", "ngTagCloud", "noosfero.init"] | |
118 | + "angular-click-outside", "toggle-switch", "ngTagCloud", "noosfero.init", "uiSwitch"] | |
119 | 119 | }) |
120 | 120 | @StateConfig([ |
121 | 121 | { | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +import {Component, Inject, provide} from "ng-forward"; | |
2 | +import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | |
3 | + | |
4 | +@Component({ | |
5 | + selector: "configbar", | |
6 | + templateUrl: "app/profile/configbar.html", | |
7 | + providers: [ | |
8 | + provide('profileService', { useClass: ProfileService }) | |
9 | + ] | |
10 | +}) | |
11 | +@Inject(ProfileService) | |
12 | +export class ConfigBarComponent { | |
13 | + profile: noosfero.Profile; | |
14 | + parentId: number; | |
15 | + | |
16 | + constructor(profileService: ProfileService) { | |
17 | + profileService.getCurrentProfile().then((profile: noosfero.Profile) => { | |
18 | + this.profile = profile; | |
19 | + }); | |
20 | + } | |
21 | +} | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +<div id="config-tool" ng-class="{'closed': !showConfig}"> | |
2 | + <a id="config-tool-cog" ng-click="showConfig = !showConfig"> | |
3 | + <i class="fa fa-cog" ng-class="{'anim-icon': showConfig}"></i> | |
4 | + </a> | |
5 | + | |
6 | + <div id="config-tool-options"> | |
7 | + <h4>{{ 'configbar.label' | translate }}</h4> | |
8 | + <div class="section-title">{{ 'configbar.section.layout' | translate }}</div> | |
9 | + <ul> | |
10 | + <li> | |
11 | + <label class="pull-left"> | |
12 | + <i class="fa fa-th-large"></i> | |
13 | + <span class="item-label">{{ 'designMode.label' | translate }}</span> | |
14 | + </label> | |
15 | + <label class="pull-right"> | |
16 | + <design-toggler></design-toggler> | |
17 | + </label> | |
18 | + </li> | |
19 | + </ul> | |
20 | + </div> | |
21 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,102 @@ |
1 | +@import "../layout/scss/mixins"; | |
2 | + | |
3 | +@include keyframes(rotating) { | |
4 | + from { | |
5 | + transform: rotate(0deg); | |
6 | + } | |
7 | + to { | |
8 | + transform: rotate(360deg); | |
9 | + } | |
10 | +} | |
11 | + | |
12 | +/* CONFIG TOOLS */ | |
13 | +#config-tool { | |
14 | + @include transition(all 0.2s ease-in-out 0s); | |
15 | + @include box-shadow(0px 1px 4px rgba(0, 0, 0, 0.3)); | |
16 | + position: fixed; | |
17 | + right: 0; | |
18 | + top: 120px; | |
19 | + min-width: 200px; | |
20 | + z-index: 1000; | |
21 | + | |
22 | + #config-tool-cog { | |
23 | + @include border-radius($border-radius-base 0 0 $border-radius-base); | |
24 | + @include transition(all 0.1s ease-in-out 0s); | |
25 | + @include box-shadow(-3px 3px 3px -2px rgba(0, 0, 0, 0.1)); | |
26 | + background: #fff; | |
27 | + cursor: pointer; | |
28 | + left: -50px; | |
29 | + padding: 10px; | |
30 | + position: absolute; | |
31 | + text-align: center; | |
32 | + width: 50px; | |
33 | + top: 0; | |
34 | + | |
35 | + i { | |
36 | + font-size: 2.2em; | |
37 | + } | |
38 | + | |
39 | + .anim-icon { | |
40 | + @include animation(rotating 0.7s ease-in-out 0s); | |
41 | + } | |
42 | + } | |
43 | + | |
44 | + &.closed { | |
45 | + right: -280px; | |
46 | + box-shadow: none; | |
47 | + | |
48 | + #config-tool-cog { | |
49 | + &:hover { | |
50 | + background-color: $primary-color; | |
51 | + color: #fff; | |
52 | + } | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + &.opened { | |
57 | + right: 0; | |
58 | + } | |
59 | + | |
60 | + .section-title { | |
61 | + font-size: 15px; | |
62 | + font-weight: bold; | |
63 | + margin: 30px 0 5px; | |
64 | + } | |
65 | + | |
66 | + #config-tool-options { | |
67 | + @include box-shadow(-3px 3px 3px -2px rgba(0, 0, 0, 0.1)); | |
68 | + background: #fff; | |
69 | + padding: 15px; | |
70 | + | |
71 | + h4 { | |
72 | + margin: 0; | |
73 | + font-size: 1.3em; | |
74 | + } | |
75 | + | |
76 | + ul { | |
77 | + list-style: none; | |
78 | + border-radius: 2px; | |
79 | + background-clip: padding-box; | |
80 | + background-color: #f1f3f2; | |
81 | + padding: 0; | |
82 | + | |
83 | + li { | |
84 | + font-size: 13px; | |
85 | + font-weight: 300; | |
86 | + padding: 10px; | |
87 | + width: 250px; | |
88 | + min-height: 50px; | |
89 | + | |
90 | + .checkbox { | |
91 | + margin: 0; | |
92 | + } | |
93 | + | |
94 | + .pull-left { | |
95 | + margin-top: 8px; | |
96 | + font-weight: normal; | |
97 | + } | |
98 | + | |
99 | + } | |
100 | + } | |
101 | + } | |
102 | +} | ... | ... |
src/app/profile/profile.component.ts
... | ... | @@ -10,7 +10,7 @@ import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; |
10 | 10 | import {NotificationService} from "../shared/services/notification.service"; |
11 | 11 | import {MyProfileComponent} from "./myprofile.component"; |
12 | 12 | import {ProfileActionsComponent} from "./profile-actions.component"; |
13 | -import {ProfileToolbarComponent} from "./profile-toolbar.component"; | |
13 | +import {ConfigBarComponent} from "./config-bar.component"; | |
14 | 14 | /** |
15 | 15 | * @ngdoc controller |
16 | 16 | * @name profile.Profile |
... | ... | @@ -44,8 +44,8 @@ import {ProfileToolbarComponent} from "./profile-toolbar.component"; |
44 | 44 | controllerAs: "vm" |
45 | 45 | }, |
46 | 46 | "toolbar@main": { |
47 | - templateUrl: "app/profile/toolbar.html", | |
48 | - controller: ProfileToolbarComponent, | |
47 | + templateUrl: "app/profile/configbar.html", | |
48 | + controller: ConfigBarComponent, | |
49 | 49 | controllerAs: "vm" |
50 | 50 | } |
51 | 51 | } |
... | ... | @@ -61,8 +61,8 @@ import {ProfileToolbarComponent} from "./profile-toolbar.component"; |
61 | 61 | controllerAs: "vm" |
62 | 62 | }, |
63 | 63 | "toolbar@main": { |
64 | - templateUrl: "app/profile/toolbar.html", | |
65 | - controller: ProfileToolbarComponent, | |
64 | + templateUrl: "app/profile/configbar.html", | |
65 | + controller: ConfigBarComponent, | |
66 | 66 | controllerAs: "vm" |
67 | 67 | } |
68 | 68 | } |
... | ... | @@ -118,8 +118,8 @@ import {ProfileToolbarComponent} from "./profile-toolbar.component"; |
118 | 118 | controllerAs: "vm" |
119 | 119 | }, |
120 | 120 | "toolbar@main": { |
121 | - templateUrl: "app/profile/toolbar.html", | |
122 | - controller: ProfileToolbarComponent, | |
121 | + templateUrl: "app/profile/configbar.html", | |
122 | + controller: ConfigBarComponent, | |
123 | 123 | controllerAs: "vm" |
124 | 124 | } |
125 | 125 | } | ... | ... |
src/languages/en.json
... | ... | @@ -6,6 +6,8 @@ |
6 | 6 | "navbar.logout": "Log Out", |
7 | 7 | "navbar.login": "Login", |
8 | 8 | "navbar.toggle_menu": "Toggle navigation", |
9 | + "configbar.label": "Configuration", | |
10 | + "configbar.section.layout": "Layout", | |
9 | 11 | "language.all": "All languages", |
10 | 12 | "language.en": "English", |
11 | 13 | "language.pt": "Portuguese", |
... | ... | @@ -77,9 +79,7 @@ |
77 | 79 | "custom_content.title": "Edit content", |
78 | 80 | "profile.custom_header.label": "Header", |
79 | 81 | "profile.custom_footer.label": "Footer", |
80 | - "designMode.label": "In Design", | |
81 | - "designMode.toggle.ON": "ON", | |
82 | - "designMode.toggle.OFF": "OFF", | |
82 | + "designMode.label": "Design mode", | |
83 | 83 | "search.results.summary": "{results, plural, one{result} other{# results}}", |
84 | 84 | "search.results.query.label": "Search therm:", |
85 | 85 | "search.label": "Search", | ... | ... |
src/languages/pt.json
... | ... | @@ -6,6 +6,8 @@ |
6 | 6 | "navbar.logout": "Sair", |
7 | 7 | "navbar.login": "Login", |
8 | 8 | "navbar.toggle_menu": "Abrir Menu", |
9 | + "configbar.label": "Configurações", | |
10 | + "configbar.section.layout": "Visual", | |
9 | 11 | "language.all": "Todos os idiomas", |
10 | 12 | "language.en": "Inglês", |
11 | 13 | "language.pt": "Português", |
... | ... | @@ -77,9 +79,7 @@ |
77 | 79 | "custom_content.title": "Editar conteúdo", |
78 | 80 | "profile.custom_header.label": "Cabeçalho", |
79 | 81 | "profile.custom_footer.label": "Rodapé", |
80 | - "designMode.label": "Modo de Edição", | |
81 | - "designMode.toggle.ON": "Ligado", | |
82 | - "designMode.toggle.OFF": "Desligado", | |
82 | + "designMode.label": "Alterar design", | |
83 | 83 | "search.results.summary": "{results, plural, one{# resultado} other{# resultados}}", |
84 | 84 | "search.results.query.label": "Termo da busca:", |
85 | 85 | "search.label": "Pesquisar", | ... | ... |