diff options
Diffstat (limited to 'client/src/app')
4 files changed, 131 insertions, 216 deletions
diff --git a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html index f71f73fec..420881f5a 100644 --- a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html +++ b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html | |||
@@ -66,13 +66,11 @@ | |||
66 | helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support the channel (membership platform...).<br /><br /> | 66 | helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support the channel (membership platform...).<br /><br /> |
67 | When a video is uploaded in this channel, the video support field will be automatically filled by this text." | 67 | When a video is uploaded in this channel, the video support field will be automatically filled by this text." |
68 | ></my-help> | 68 | ></my-help> |
69 | |||
69 | <my-markdown-textarea | 70 | <my-markdown-textarea |
70 | id="support" formControlName="support" textareaMaxWidth="500px" markdownType="enhanced" | 71 | id="support" formControlName="support" textareaMaxWidth="500px" markdownType="enhanced" |
71 | [classes]="{ 'input-error': formErrors['support'] }" | 72 | [formError]="formErrors['support']" |
72 | ></my-markdown-textarea> | 73 | ></my-markdown-textarea> |
73 | <div *ngIf="formErrors.support" class="form-error"> | ||
74 | {{ formErrors.support }} | ||
75 | </div> | ||
76 | </div> | 74 | </div> |
77 | 75 | ||
78 | <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()"> | 76 | <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()"> |
diff --git a/client/src/app/shared/shared-forms/markdown-textarea.component.html b/client/src/app/shared/shared-forms/markdown-textarea.component.html index 7c2a42791..afb046c7f 100644 --- a/client/src/app/shared/shared-forms/markdown-textarea.component.html +++ b/client/src/app/shared/shared-forms/markdown-textarea.component.html | |||
@@ -1,7 +1,8 @@ | |||
1 | <div class="root" [ngClass]="{ 'maximized': isMaximized }" [ngStyle]="{ 'max-width': textareaMaxWidth }"> | 1 | <div class="root" [ngClass]="{ 'maximized': isMaximized }" [ngStyle]="{ 'max-width': textareaMaxWidth }"> |
2 | |||
2 | <textarea #textarea | 3 | <textarea #textarea |
3 | [(ngModel)]="content" (ngModelChange)="onModelChange()" | 4 | [(ngModel)]="content" (ngModelChange)="onModelChange()" |
4 | class="form-control" [ngClass]="classes" | 5 | class="form-control" [ngClass]="{ 'input-error': formError }" |
5 | [attr.disabled]="disabled || null" | 6 | [attr.disabled]="disabled || null" |
6 | [ngStyle]="{ height: textareaHeight }" | 7 | [ngStyle]="{ height: textareaHeight }" |
7 | [id]="name" [name]="name"> | 8 | [id]="name" [name]="name"> |
@@ -25,14 +26,18 @@ | |||
25 | </ng-template> | 26 | </ng-template> |
26 | </ng-container> | 27 | </ng-container> |
27 | 28 | ||
28 | <my-button | 29 | <my-global-icon |
29 | *ngIf="!isMaximized" [title]="maximizeInText" className="maximize-button" icon="fullscreen" (click)="onMaximizeClick()" [disabled]="disabled" | 30 | *ngIf="!isMaximized" role="button" [ngbTooltip]="maximizeInText" |
30 | ></my-button> | 31 | class="maximize-button" iconName="fullscreen" (click)="onMaximizeClick()" [ngClass]="{ disabled: disabled }" |
32 | ></my-global-icon> | ||
31 | 33 | ||
32 | <my-button | 34 | <my-global-icon |
33 | *ngIf="isMaximized" [title]="maximizeOutText" className="maximize-button" icon="exit-fullscreen" (click)="onMaximizeClick()" [disabled]="disabled" | 35 | *ngIf="isMaximized" role="button" [ngbTooltip]="maximizeOutText" |
34 | ></my-button> | 36 | class="maximize-button" iconName="exit-fullscreen" (click)="onMaximizeClick()" [ngClass]="{ disabled: disabled }" |
37 | ></my-global-icon> | ||
35 | </div> | 38 | </div> |
36 | 39 | ||
37 | <div [ngbNavOutlet]="nav"></div> | 40 | <div [ngbNavOutlet]="nav"></div> |
41 | |||
42 | <div *ngIf="!isMaximized && formError" class="form-error">{{ formError }}</div> | ||
38 | </div> | 43 | </div> |
diff --git a/client/src/app/shared/shared-forms/markdown-textarea.component.scss b/client/src/app/shared/shared-forms/markdown-textarea.component.scss index 116630d8a..c68c2c241 100644 --- a/client/src/app/shared/shared-forms/markdown-textarea.component.scss +++ b/client/src/app/shared/shared-forms/markdown-textarea.component.scss | |||
@@ -6,260 +6,169 @@ $nav-preview-tab-height: 30px; | |||
6 | $base-padding: 15px; | 6 | $base-padding: 15px; |
7 | $input-border-radius: 3px; | 7 | $input-border-radius: 3px; |
8 | 8 | ||
9 | @mixin in-small-view { | 9 | .root { |
10 | .root { | 10 | display: flex; |
11 | display: flex; | 11 | flex-direction: column; |
12 | flex-direction: column; | ||
13 | 12 | ||
14 | textarea { | 13 | textarea { |
15 | @include peertube-textarea(100%, 150px); | 14 | @include peertube-textarea(100%, 150px); |
16 | 15 | ||
17 | background-color: pvar(--markdownTextareaBackgroundColor); | 16 | background-color: pvar(--markdownTextareaBackgroundColor); |
18 | 17 | ||
19 | font-family: monospace; | 18 | font-family: monospace; |
20 | font-size: 13px; | 19 | font-size: 13px; |
21 | border-bottom: 0; | 20 | border-bottom: 0; |
22 | border-bottom-left-radius: unset; | 21 | border-bottom-left-radius: 0; |
23 | border-bottom-right-radius: unset; | 22 | border-bottom-right-radius: 0; |
24 | } | 23 | } |
25 | 24 | ||
26 | .nav-preview { | 25 | .nav-preview { |
27 | @include padding-left(10px); | 26 | padding: 10px; |
28 | @include padding-right(10px); | ||
29 | 27 | ||
30 | display: block; | 28 | border: 1px solid $input-border-color; |
31 | text-align: end; | 29 | border-top: 1px dashed $input-border-color; |
32 | padding-top: 10px; | ||
33 | padding-bottom: 10px; | ||
34 | border-top: 1px dashed $input-border-color; | ||
35 | border-left: 1px solid $input-border-color; | ||
36 | border-right: 1px solid $input-border-color; | ||
37 | border-bottom: 1px solid $input-border-color; | ||
38 | border-bottom-right-radius: $input-border-radius; | ||
39 | |||
40 | border-bottom-left-radius: $input-border-radius; | ||
41 | ::ng-deep { | ||
42 | .nav-link { | ||
43 | display: none !important; | ||
44 | } | ||
45 | 30 | ||
46 | .maximize-button { | 31 | border-bottom-right-radius: $input-border-radius; |
47 | padding: 0 7px; | 32 | border-bottom-left-radius: $input-border-radius; |
48 | cursor: pointer; | ||
49 | |||
50 | svg { | ||
51 | stroke: var(--mainForegroundColor); | ||
52 | opacity: 0.7; | ||
53 | } | ||
54 | |||
55 | &:hover, | ||
56 | &:active { | ||
57 | svg { | ||
58 | opacity: 1; | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | 33 | ||
65 | ::ng-deep { | 34 | display: flex; |
66 | .tab-content { | 35 | flex-grow: 1; |
67 | display: none; | 36 | border-bottom-left-radius: unset; |
68 | } | 37 | border-bottom-right-radius: unset; |
69 | } | 38 | border-bottom: 2px solid pvar(--mainColor); |
70 | } | ||
71 | } | ||
72 | 39 | ||
73 | @mixin nav-preview-medium { | 40 | .maximize-button { |
74 | display: flex; | 41 | @include margin-left(15px); |
75 | flex-grow: 1; | ||
76 | border-bottom-left-radius: unset; | ||
77 | border-bottom-right-radius: unset; | ||
78 | border-bottom: 2px solid pvar(--mainColor); | ||
79 | 42 | ||
80 | :first-child { | 43 | opacity: 0.6; |
81 | @include margin-left(auto); | 44 | cursor: default; |
82 | } | ||
83 | 45 | ||
84 | ::ng-deep { | 46 | &:not(.disabled) { |
85 | .nav-link { | 47 | cursor: pointer; |
86 | display: flex !important; | ||
87 | align-items: center; | ||
88 | height: $nav-preview-tab-height !important; | ||
89 | padding: 0 15px !important; | ||
90 | font-size: 85% !important; | ||
91 | opacity: .7; | ||
92 | } | ||
93 | 48 | ||
94 | .maximize-button { | 49 | &:hover, |
95 | @include margin-left(5px); | 50 | &:active { |
51 | opacity: 1; | ||
52 | } | ||
53 | } | ||
96 | } | 54 | } |
97 | } | 55 | } |
98 | } | ||
99 | 56 | ||
100 | @mixin content-preview-base { | 57 | .nav-pills { |
101 | display: block; | 58 | display: flex; |
102 | min-height: 75px; | 59 | align-items: center; |
103 | padding: $base-padding; | 60 | justify-content: flex-end; |
104 | overflow-y: auto; | ||
105 | word-wrap: break-word; | ||
106 | } | ||
107 | 61 | ||
108 | @mixin maximized-base { | 62 | > * { |
109 | $nav-preview-vertical-padding: 40px; | 63 | font-size: 0.9em !important; |
64 | } | ||
65 | } | ||
110 | 66 | ||
111 | flex-direction: row; | 67 | .tab-content { |
112 | z-index: #{z(header) - 1}; | 68 | min-height: 75px; |
113 | position: fixed; | 69 | max-height: 210px; |
114 | top: $header-height; | 70 | padding: $base-padding; |
115 | left: $menu-width; | ||
116 | max-height: none !important; | ||
117 | max-width: none !important; | ||
118 | width: calc(100% - #{$menu-width}); | ||
119 | height: calc(100vh - #{$header-height}) !important; | ||
120 | 71 | ||
121 | .nav-preview { | 72 | overflow-y: auto; |
122 | @include nav-preview-medium(); | 73 | word-wrap: break-word; |
123 | @include padding-right(0); | ||
124 | @include padding-left(0); | ||
125 | 74 | ||
126 | padding-top: math.div($nav-preview-vertical-padding, 2); | 75 | border: 1px solid $input-border-color; |
127 | padding-bottom: math.div($nav-preview-vertical-padding, 2); | ||
128 | position: absolute; | ||
129 | background-color: pvar(--mainBackgroundColor); | ||
130 | width: 100% !important; | ||
131 | border-top: 0; | 76 | border-top: 0; |
132 | border-left: 0; | ||
133 | border-right: 0; | ||
134 | 77 | ||
135 | :last-child { | 78 | border-bottom-left-radius: $input-border-radius; |
136 | @include margin-right(pvar(--horizontalMarginContent)); | 79 | border-bottom-right-radius: $input-border-radius; |
137 | } | ||
138 | } | 80 | } |
139 | 81 | ||
140 | ::ng-deep .tab-content { | 82 | &.maximized { |
141 | @include content-preview-base(); | 83 | z-index: #{z(header) - 1}; |
142 | background-color: pvar(--mainBackgroundColor); | 84 | position: fixed; |
143 | scrollbar-color: pvar(--actionButtonColor) pvar(--mainBackgroundColor); | 85 | top: $header-height; |
144 | } | 86 | left: $menu-width; |
145 | 87 | ||
146 | textarea, | ||
147 | ::ng-deep .tab-content { | ||
148 | max-height: none !important; | 88 | max-height: none !important; |
149 | max-width: none !important; | 89 | max-width: none !important; |
150 | margin-top: #{$nav-preview-tab-height + $nav-preview-vertical-padding} !important; | 90 | width: calc(100% - #{$menu-width}); |
151 | height: calc(100vh - #{$header-height + $nav-preview-tab-height + $nav-preview-vertical-padding}) !important; | 91 | height: calc(100vh - #{$header-height}); |
152 | width: 50% !important; | ||
153 | border: 0 !important; | ||
154 | border-radius: unset !important; | ||
155 | } | ||
156 | |||
157 | :host-context(.expanded) { | ||
158 | .root.maximized { | ||
159 | left: 0; | ||
160 | width: 100%; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | 92 | ||
165 | @mixin maximized-in-small-view { | 93 | display: grid; |
166 | .root.maximized { | 94 | grid-template-rows: auto 1fr; |
167 | @include maximized-base(); | 95 | grid-template-columns: 1fr 1fr; |
168 | 96 | ||
169 | textarea { | 97 | background-color: pvar(--mainBackgroundColor); |
170 | display: none; | ||
171 | } | ||
172 | |||
173 | ::ng-deep .tab-content { | ||
174 | width: 100% !important; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | 98 | ||
179 | @mixin maximized-tabs-in-mobile-view { | ||
180 | // Ellipsis on tabs for mobile view | ||
181 | .root.maximized { | ||
182 | .nav-preview { | 99 | .nav-preview { |
183 | ::ng-deep .nav-link { | 100 | grid-row: 1; |
184 | @include ellipsis(); | 101 | grid-column: 1 / 3; |
185 | @include margin-right(10px !important); | ||
186 | 102 | ||
187 | display: block !important; | 103 | border: 0; |
188 | max-width: 45% !important; | 104 | border-bottom: 2px solid pvar(--mainColor); |
189 | padding: 5px 0 !important; | ||
190 | text-align: center; | ||
191 | 105 | ||
192 | &:not(.active) { | 106 | padding: 20px 0; |
193 | max-width: 15% !important; | 107 | width: 100% !important; |
194 | } | ||
195 | 108 | ||
196 | &.active { | 109 | .maximize-button { |
197 | padding: 5px 15px !important; | 110 | @include margin-right(15px); |
198 | } | ||
199 | } | 111 | } |
200 | } | 112 | } |
201 | } | ||
202 | } | ||
203 | 113 | ||
204 | @mixin in-medium-view { | 114 | textarea { |
205 | .root { | 115 | grid-column: 1; |
206 | .nav-preview { | 116 | |
207 | @include nav-preview-medium(); | 117 | border: 0; |
118 | border-right: 1px dashed $input-border-color; | ||
119 | |||
120 | resize: none; | ||
208 | } | 121 | } |
209 | 122 | ||
210 | ::ng-deep .tab-content { | 123 | ::ng-deep .tab-content { |
211 | @include content-preview-base(); | 124 | grid-column: 2; |
212 | max-height: 210px; | ||
213 | border-bottom: 1px solid $input-border-color; | ||
214 | border-left: 1px solid $input-border-color; | ||
215 | border-right: 1px solid $input-border-color; | ||
216 | border-bottom-left-radius: $input-border-radius; | ||
217 | border-bottom-right-radius: $input-border-radius; | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | 125 | ||
222 | @mixin maximized-in-medium-view { | 126 | border: 0; |
223 | .root.maximized { | ||
224 | @include maximized-base(); | ||
225 | 127 | ||
226 | textarea { | ||
227 | display: block; | 128 | display: block; |
228 | padding: $base-padding; | 129 | overflow-y: auto; |
229 | border-right: 1px dashed $input-border-color !important; | 130 | word-wrap: break-word; |
230 | resize: none; | ||
231 | scrollbar-color: pvar(--actionButtonColor) pvar(--markdownTextareaBackgroundColor); | ||
232 | 131 | ||
233 | &:focus { | 132 | scrollbar-color: pvar(--actionButtonColor) pvar(--mainBackgroundColor); |
234 | box-shadow: none; | ||
235 | } | ||
236 | } | 133 | } |
237 | } | ||
238 | } | ||
239 | 134 | ||
240 | @include in-small-view(); | 135 | textarea, |
241 | @include maximized-in-small-view(); | 136 | ::ng-deep .tab-content { |
137 | grid-row: 2; | ||
242 | 138 | ||
243 | @media only screen and (max-width: $mobile-view) { | 139 | height: 100% !important; |
244 | @include maximized-tabs-in-mobile-view(); | 140 | max-height: none !important; |
245 | } | 141 | border-radius: 0; |
246 | 142 | ||
247 | @media only screen and (max-width: #{$mobile-view + $menu-width}) { | 143 | padding: 15px; |
248 | :host-context(.main-col:not(.expanded)) { | 144 | } |
249 | @include maximized-tabs-in-mobile-view(); | 145 | |
250 | } | 146 | @media screen and (max-width: $mobile-view) { |
251 | } | 147 | grid-template-rows: auto 45% 1fr; |
148 | grid-template-columns: 1fr; | ||
149 | |||
150 | .nav-preview { | ||
151 | grid-column: 1; | ||
152 | } | ||
252 | 153 | ||
253 | @media only screen and (min-width: $small-view) { | 154 | textarea { |
254 | @include maximized-in-medium-view(); | 155 | grid-row: 2; |
156 | grid-column: 1; | ||
157 | border: 0; | ||
158 | border-bottom: 1px dashed $input-border-color;; | ||
159 | } | ||
255 | 160 | ||
256 | :host-context(.expanded) { | 161 | ::ng-deep .tab-content { |
257 | @include in-medium-view(); | 162 | grid-column: 1; |
163 | grid-row: 3; | ||
164 | } | ||
165 | } | ||
258 | } | 166 | } |
259 | } | 167 | } |
260 | 168 | ||
261 | @media only screen and (min-width: #{$small-view + $menu-width}) { | 169 | :host-context(.main-col.expanded) { |
262 | :host-context(.main-col:not(.expanded)) { | 170 | .root.maximized { |
263 | @include in-medium-view(); | 171 | left: 0; |
172 | width: 100%; | ||
264 | } | 173 | } |
265 | } | 174 | } |
diff --git a/client/src/app/shared/shared-forms/markdown-textarea.component.ts b/client/src/app/shared/shared-forms/markdown-textarea.component.ts index dcb5d20da..5a603c157 100644 --- a/client/src/app/shared/shared-forms/markdown-textarea.component.ts +++ b/client/src/app/shared/shared-forms/markdown-textarea.component.ts | |||
@@ -24,6 +24,7 @@ import { Video } from '@shared/models' | |||
24 | export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit { | 24 | export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit { |
25 | @Input() content = '' | 25 | @Input() content = '' |
26 | 26 | ||
27 | @Input() formError: string | ||
27 | @Input() classes: string[] | { [klass: string]: any[] | any } = [] | 28 | @Input() classes: string[] | { [klass: string]: any[] | any } = [] |
28 | 29 | ||
29 | @Input() textareaMaxWidth = '100%' | 30 | @Input() textareaMaxWidth = '100%' |
@@ -93,6 +94,8 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit { | |||
93 | } | 94 | } |
94 | 95 | ||
95 | onMaximizeClick () { | 96 | onMaximizeClick () { |
97 | if (this.disabled) return | ||
98 | |||
96 | this.isMaximized = !this.isMaximized | 99 | this.isMaximized = !this.isMaximized |
97 | 100 | ||
98 | // Make sure textarea have the focus | 101 | // Make sure textarea have the focus |