]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/sass/include/_mixins.scss
7a100a53d7a8bc58c8f350591f41ae678ebadfd3
[github/Chocobozzz/PeerTube.git] / client / src / sass / include / _mixins.scss
1 @use 'sass:math';
2 @use '_variables' as *;
3
4 @import '_bootstrap-mixins';
5
6 @mixin disable-default-a-behaviour {
7 &:hover,
8 &:focus,
9 &:active {
10 text-decoration: none !important;
11 }
12
13 &:focus:not(.focus-visible) {
14 outline: none !important;
15 }
16 }
17
18 @mixin disable-outline {
19 &:focus:not(.focus-visible) {
20 outline: none !important;
21 }
22 }
23
24 @mixin ellipsis {
25 white-space: nowrap;
26 overflow: hidden;
27 text-overflow: ellipsis;
28 }
29
30 @mixin muted {
31 color: pvar(--greyForegroundColor) !important;
32 }
33
34 @mixin fade-text ($fade-after, $background-color) {
35 position: relative;
36 overflow: hidden;
37
38 &::after {
39 content: '';
40 pointer-events: none;
41 width: 100%;
42 height: 100%;
43 position: absolute;
44 left: 0;
45 top: 0;
46 background: linear-gradient(transparent $fade-after, $background-color);
47 }
48 }
49
50 @mixin peertube-word-wrap ($with-hyphen: true) {
51 word-break: break-word;
52 word-wrap: break-word;
53 overflow-wrap: break-word;
54
55 @if $with-hyphen {
56 hyphens: auto;
57 }
58 }
59
60 @mixin apply-svg-color ($color) {
61 ::ng-deep .feather,
62 ::ng-deep .material,
63 ::ng-deep .misc {
64 color: $color;
65 }
66 }
67
68 @mixin fill-svg-color ($color) {
69 ::ng-deep svg {
70 path {
71 fill: $color;
72 }
73 }
74 }
75
76 @mixin button-focus($color) {
77 &:focus,
78 &.focus-visible {
79 box-shadow: #{$focus-box-shadow-form} $color;
80 }
81 }
82
83 @mixin rounded-line-height-1-5 ($font-size) {
84 line-height: $font-size + math.round(math.div($font-size, 2));
85 }
86
87 @mixin peertube-input-text($width, $font-size: $form-input-font-size) {
88 @include rounded-line-height-1-5($font-size);
89
90 font-size: $font-size;
91
92 padding: 3px 15px;
93 display: inline-block;
94 width: $width;
95 max-width: $width;
96 color: pvar(--inputForegroundColor);
97 background-color: pvar(--inputBackgroundColor);
98 border: 1px solid pvar(--inputBorderColor);
99 border-radius: 3px;
100
101 &::placeholder {
102 color: pvar(--inputPlaceholderColor);
103 }
104
105 &[readonly] {
106 opacity: 0.7;
107 }
108
109 @media screen and (max-width: calc(#{$width} + 40px)) {
110 width: 100%;
111 }
112 }
113
114 @mixin peertube-textarea ($width, $height) {
115 @include peertube-input-text($width);
116
117 color: pvar(--textareaForegroundColor) !important;
118 background-color: pvar(--textareaBackgroundColor) !important;
119 height: $height;
120 padding: 5px 15px;
121 }
122
123 @mixin orange-button {
124 @include button-focus(pvar(--mainColorLightest));
125
126 &,
127 &:active,
128 &:focus {
129 color: #fff;
130 background-color: pvar(--mainColor);
131 }
132
133 &:hover {
134 color: #fff;
135 background-color: pvar(--mainHoverColor);
136 }
137
138 &[disabled],
139 &.disabled {
140 cursor: default;
141 color: #fff;
142 background-color: pvar(--inputBorderColor);
143 }
144
145 my-global-icon {
146 @include apply-svg-color(#fff);
147 }
148 }
149
150 @mixin orange-button-inverted {
151 @include button-focus(pvar(--mainColorLightest));
152
153 padding: 2px 13px;
154 border: 2px solid pvar(--mainColor);
155 font-weight: $font-semibold;
156
157 &,
158 &:active,
159 &:focus {
160 color: pvar(--mainColor);
161 background-color: pvar(--mainBackgroundColor);
162 }
163
164 &:hover {
165 color: pvar(--mainColor);
166 background-color: pvar(--mainColorLightest);
167 }
168
169 &[disabled],
170 &.disabled {
171 cursor: default;
172 color: pvar(--mainColor);
173 background-color: pvar(--inputBorderColor);
174 }
175
176 my-global-icon {
177 @include apply-svg-color(pvar(--mainColor));
178 }
179 }
180
181 @mixin tertiary-button {
182 @include button-focus($grey-button-outline-color);
183
184 color: pvar(--greyForegroundColor);
185 background-color: transparent;
186
187 &[disabled],
188 .disabled {
189 cursor: default;
190 }
191
192 my-global-icon {
193 @include apply-svg-color(transparent);
194 }
195 }
196
197 @mixin grey-button {
198 @include button-focus($grey-button-outline-color);
199
200 background-color: pvar(--greyBackgroundColor);
201 color: pvar(--greyForegroundColor);
202
203 &:hover,
204 &:active,
205 &:focus,
206 &[disabled],
207 &.disabled {
208 color: pvar(--greyForegroundColor);
209 background-color: pvar(--greySecondaryBackgroundColor);
210 }
211
212 &[disabled],
213 &.disabled {
214 cursor: default;
215 }
216
217 my-global-icon {
218 @include apply-svg-color(pvar(--greyForegroundColor));
219 }
220 }
221
222 @mixin danger-button {
223 $color: lighten($color: #c54130, $amount: 10);
224 $text: #fff6f5;
225
226 @include button-focus(scale-color($color, $alpha: -95%));
227
228 background-color: $color;
229 color: $text;
230
231 &:hover,
232 &:active,
233 &:focus,
234 &[disabled],
235 &.disabled {
236 background-color: lighten($color: $color, $amount: 10);
237 }
238
239 &[disabled],
240 &.disabled {
241 cursor: default;
242 }
243
244 my-global-icon {
245 @include apply-svg-color($text);
246 }
247 }
248
249 @mixin peertube-button {
250 @include rounded-line-height-1-5($button-font-size);
251
252 padding: 4px 13px;
253
254 border: 0;
255 font-weight: $font-semibold;
256
257 // Because of primeng that redefines border-radius of all input[type="..."]
258 border-radius: 3px !important;
259
260 text-align: center;
261 cursor: pointer;
262
263 font-size: $button-font-size;
264
265 my-global-icon + * {
266 @include margin-right(4px);
267 @include margin-left(4px);
268 }
269 }
270
271 @mixin peertube-button-big {
272 height: auto;
273 padding: 10px 25px;
274 font-size: 18px;
275 line-height: 1.2;
276 border: 0;
277 font-weight: $font-semibold;
278
279 // Because of primeng that redefines border-radius of all input[type="..."]
280 border-radius: 3px !important;
281 }
282
283 @mixin peertube-button-link {
284 @include disable-default-a-behaviour;
285 @include peertube-button;
286
287 display: inline-block;
288 }
289
290 @mixin peertube-button-big-link {
291 @include disable-default-a-behaviour;
292 @include peertube-button-big;
293
294 display: inline-block;
295 }
296
297 @mixin peertube-button-outline {
298 @include disable-default-a-behaviour;
299 @include peertube-button;
300
301 display: inline-block;
302 border: 1px solid;
303 }
304
305 @mixin button-with-icon($width: 20px, $margin-right: 3px, $top: -1px) {
306 my-global-icon {
307 @include margin-right($margin-right);
308
309 position: relative;
310 width: $width;
311 top: $top;
312 }
313 }
314
315 @mixin peertube-file {
316 position: relative;
317 overflow: hidden;
318 display: inline-block;
319
320 input[type=file] {
321 position: absolute;
322 top: 0;
323 right: 0;
324 width: 100%;
325 height: 100%;
326 font-size: 100px;
327 text-align: end;
328 filter: alpha(opacity=0);
329 opacity: 0;
330 outline: none;
331 background: pvar(--mainBackgroundColor);
332 cursor: inherit;
333 display: block;
334 }
335 }
336
337 @mixin peertube-button-file ($width) {
338 @include peertube-file;
339 @include peertube-button;
340
341 width: $width;
342 }
343
344 @mixin icon ($size) {
345 display: inline-block;
346 background-repeat: no-repeat;
347 background-size: contain;
348 width: $size;
349 height: $size;
350 vertical-align: middle;
351 cursor: pointer;
352 }
353
354 @mixin responsive-width ($width) {
355 width: $width;
356
357 @media screen and (max-width: $width) {
358 width: 100%;
359 }
360 }
361
362 @mixin peertube-select-container ($width) {
363 padding: 0;
364 margin: 0;
365 width: $width;
366 border-radius: 3px;
367 color: pvar(--inputForegroundColor);
368 background: pvar(--inputBackgroundColor);
369 position: relative;
370 height: min-content;
371
372 &.disabled {
373 background-color: #E5E5E5;
374
375 select {
376 cursor: default;
377 }
378 }
379
380 select[disabled] {
381 background-color: #f9f9f9;
382 }
383
384 @media screen and (max-width: $width) {
385 width: 100%;
386 }
387
388 &::after {
389 top: 50%;
390 right: calc(0% + 15px);
391 content: ' ';
392 height: 0;
393 width: 0;
394 position: absolute;
395 pointer-events: none;
396 border: 5px solid rgba(0, 0, 0, 0);
397 border-top-color: pvar(--mainForegroundColor);
398 margin-top: -2px;
399 z-index: 100;
400 }
401
402 select {
403 @include rounded-line-height-1-5($form-input-font-size);
404
405 font-size: $form-input-font-size;
406
407 padding: 3px 35px 3px 12px;
408 position: relative;
409 border: 1px solid pvar(--inputBorderColor);
410 background: transparent none;
411 appearance: none;
412 text-overflow: ellipsis;
413 color: pvar(--mainForegroundColor);
414
415 &:focus {
416 outline: none;
417 }
418
419 &:-moz-focusring {
420 color: transparent;
421 text-shadow: 0 0 0 #000;
422 }
423
424 option {
425 color: #000;
426
427 &[value=undefined] {
428 font-weight: $font-semibold;
429 }
430 }
431 }
432
433 &.peertube-select-button {
434 @include grey-button;
435
436 select {
437 font-weight: $font-semibold;
438 color: pvar(--greyForegroundColor);
439 border: 0;
440
441 // No border, add +1 to vertical padding
442 padding: 4px 35px 4px 12px;
443 }
444 }
445 }
446
447 // Thanks: https://codepen.io/manabox/pen/raQmpL
448 @mixin peertube-radio-container {
449 label {
450 font-size: $form-input-font-size;
451 }
452
453 [type=radio]:checked,
454 [type=radio]:not(:checked) {
455 position: absolute;
456 opacity: 0;
457 cursor: pointer;
458 height: 0;
459 width: 0;
460 }
461
462 [type=radio]:checked + label,
463 [type=radio]:not(:checked) + label {
464 position: relative;
465 padding-left: 28px;
466 cursor: pointer;
467 line-height: 20px;
468 display: inline-block;
469 font-weight: $font-regular;
470 }
471
472 [type=radio]:checked + label::before,
473 [type=radio]:not(:checked) + label::before {
474 content: '';
475 position: absolute;
476 left: 0;
477 top: 0;
478 width: 18px;
479 height: 18px;
480 border: 1px solid pvar(--inputBorderColor);
481 border-radius: 100%;
482 background: #fff;
483 }
484
485 [type=radio]:checked + label::after,
486 [type=radio]:not(:checked) + label::after {
487 content: '';
488 width: 10px;
489 height: 10px;
490 background: pvar(--mainColor);
491 position: absolute;
492 top: 4px;
493 left: 4px;
494 border-radius: 100%;
495 transition: all 0.2s ease;
496 }
497 [type=radio]:not(:checked) + label::after {
498 opacity: 0;
499 transform: scale(0);
500 }
501 [type=radio]:checked + label::after {
502 opacity: 1;
503 transform: scale(1);
504 }
505
506 .form-group-description {
507 display: block;
508 margin-top: -7px;
509 margin-bottom: 10px;
510 margin-left: 29px;
511 }
512 }
513
514 @mixin peertube-checkbox ($border-width) {
515 opacity: 0;
516 position: absolute;
517
518 &:focus + span {
519 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest);
520 }
521
522 + span {
523 position: relative;
524 width: 18px;
525 min-width: 18px;
526 height: 18px;
527 border: $border-width solid pvar(--inputBorderColor);
528 border-radius: 3px;
529 vertical-align: middle;
530 cursor: pointer;
531
532 &::after {
533 content: '';
534 position: absolute;
535 top: calc(2px - #{$border-width});
536 left: 5px;
537 width: 5px;
538 height: 12px;
539 opacity: 0;
540 transform: rotate(45deg) scale(0);
541 border-right: 2px solid pvar(--mainBackgroundColor);
542 border-bottom: 2px solid pvar(--mainBackgroundColor);
543 }
544 }
545
546 &:checked + span {
547 border-color: transparent;
548 background: pvar(--mainColor);
549 animation: jelly 0.6s ease;
550
551 &::after {
552 opacity: 1;
553 transform: rotate(45deg) scale(1);
554 }
555 }
556
557 + span + span {
558 @include margin-left(5px);
559
560 font-weight: $font-regular;
561 cursor: pointer;
562 display: inline;
563 }
564
565 &[disabled] + span,
566 &[disabled] + span + span {
567 opacity: 0.5;
568 cursor: default;
569 }
570 }
571
572 @mixin actor-avatar-size ($size) {
573 display: inline-block;
574 width: $size;
575 height: $size;
576 min-width: $size;
577 min-height: $size;
578 }
579
580 @mixin actor-counters ($separator-margin: 10px) {
581 color: pvar(--greyForegroundColor);
582 display: flex;
583 align-items: center;
584
585 > *:not(:last-child)::after {
586 content: '•';
587 margin: 0 $separator-margin;
588 color: pvar(--mainColor);
589 }
590 }
591
592 @mixin in-content-small-title {
593 text-transform: uppercase;
594 color: pvar(--mainColor);
595 font-weight: $font-bold;
596 font-size: 13px;
597 }
598
599 @mixin settings-big-title {
600 text-transform: uppercase;
601 color: pvar(--mainColor);
602 font-weight: $font-bold;
603 font-size: 1rem;
604 margin-bottom: 10px;
605 }
606
607 @mixin row-blocks ($column-responsive: true, $min-height: 130px, $separator: true) {
608 display: flex;
609 min-height: $min-height;
610 padding-bottom: 20px;
611 margin-bottom: 20px;
612
613 @if $separator {
614 border-bottom: 1px solid pvar(--inputBorderColor);
615 }
616
617 @media screen and (max-width: $small-view) {
618 @if $column-responsive {
619 flex-direction: column;
620 height: auto;
621 align-items: center;
622 } @else {
623 min-height: initial;
624 padding-bottom: 10px;
625 margin-bottom: 10px;
626 }
627 }
628 }
629
630 @mixin dropdown-with-icon-item {
631 padding: 6px 15px;
632
633 my-global-icon {
634 @include margin-right(10px);
635
636 width: 22px;
637 opacity: .7;
638 position: relative;
639 top: -2px;
640 }
641 }
642
643 @mixin progressbar($small: false) {
644 background-color: pvar(--greyBackgroundColor);
645 display: flex;
646 height: 1rem;
647 overflow: hidden;
648 font-size: 0.75rem;
649 border-radius: 0.25rem;
650 position: relative;
651
652 span {
653 position: absolute;
654 color: pvar(--greyForegroundColor);
655
656 @if $small {
657 top: -1px;
658 }
659
660 &:nth-of-type(1) {
661 left: .2rem;
662 }
663 &:nth-of-type(2) {
664 right: .2rem;
665 }
666 }
667
668 .progress-bar {
669 color: pvar(--mainBackgroundColor);
670 background-color: pvar(--mainColor);
671 display: flex;
672 flex-direction: column;
673 justify-content: center;
674 text-align: center;
675 white-space: nowrap;
676 transition: width 0.6s ease;
677
678 &.red {
679 background-color: lighten($color: #c54130, $amount: 10);
680 }
681 }
682 }
683
684 @mixin breadcrumb {
685 display: flex;
686 flex-wrap: wrap;
687 padding: 0;
688 margin-bottom: 1rem;
689 list-style: none;
690 font-weight: $font-semibold;
691
692 .breadcrumb-item {
693 display: flex;
694
695 a {
696 color: pvar(--mainColor);
697 }
698
699 + .breadcrumb-item {
700 @include padding-left(0.5rem);
701
702 &::before {
703 @include padding-right(0.5rem);
704
705 display: inline-block;
706 color: #6c757d;
707 content: '/';
708 }
709 }
710
711 &.active {
712 color: #6c757d;
713 }
714 }
715 }
716
717 @mixin dashboard {
718 display: flex;
719 flex-wrap: wrap;
720 margin: 0 -5px;
721
722 > div {
723 box-sizing: border-box;
724 flex: 0 0 percentage(math.div(1, 3));
725 padding: 0 5px;
726 margin-bottom: 10px;
727
728 > a {
729 @include disable-default-a-behaviour;
730
731 text-decoration: none;
732 color: inherit;
733 display: block;
734 font-size: 18px;
735
736 &:active,
737 &:focus,
738 &:hover {
739 opacity: .8;
740 }
741 }
742
743 > a,
744 > div {
745 padding: 20px;
746 background: pvar(--submenuBackgroundColor);
747 border-radius: 4px;
748 box-sizing: border-box;
749 height: 100%;
750 }
751 }
752
753 .dashboard-num,
754 .dashboard-text {
755 text-align: center;
756 font-size: 130%;
757 color: pvar(--mainForegroundColor);
758 line-height: 30px;
759 margin-bottom: 20px;
760 }
761
762 .dashboard-label {
763 font-size: 90%;
764 color: pvar(--inputPlaceholderColor);
765 text-align: center;
766 }
767 }
768
769 @mixin divider($color: pvar(--submenuBackgroundColor), $background: pvar(--mainBackgroundColor)) {
770 width: 95%;
771 border-top: .05rem solid $color;
772 height: .05rem;
773 text-align: center;
774 display: block;
775 position: relative;
776
777 &[data-content] {
778 margin: .8rem 0;
779
780 &::after {
781 background: $background;
782 color: $color;
783 content: attr(data-content);
784 display: inline-block;
785 font-size: .7rem;
786 padding: 0 .4rem;
787 transform: translateY(-.65rem);
788 }
789 }
790 }
791
792 @mixin chip {
793 --avatar-size: 1.2rem;
794
795 display: inline-flex;
796 color: pvar(--mainForegroundColor);
797 height: var(--avatar-size);
798 max-width: 320px;
799 overflow: hidden;
800 text-decoration: none;
801 text-overflow: ellipsis;
802 vertical-align: middle;
803 white-space: nowrap;
804
805 my-actor-avatar {
806 @include margin-right(.2rem);
807
808 border-radius: 5rem;
809 width: var(--avatar-size);
810 height: var(--avatar-size);
811 }
812
813 &.two-lines {
814 --avatar-size: 2rem;
815
816 font-size: 14px;
817 line-height: 1rem;
818
819 my-actor-avatar {
820 display: inline-block;
821 }
822
823 > div {
824 display: flex;
825 flex-direction: column;
826 justify-content: center;
827 }
828 }
829 }
830
831 // applies ratio (default to 16:9) to a child element (using $selector) only using
832 // an immediate's parent size. This allows to set a ratio without explicit
833 // dimensions, as width/height cannot be computed from each other.
834 @mixin block-ratio ($selector: 'div', $inverted-ratio: math.div(9, 16)) {
835 $padding-percent: percentage($inverted-ratio);
836
837 position: relative;
838 height: 0;
839 width: 100%;
840 padding-top: $padding-percent;
841
842 #{$selector} {
843 position: absolute;
844 width: 100%;
845 height: 100%;
846 top: 0;
847
848 @content;
849 }
850 }
851
852 @mixin sub-menu-h1 {
853 ::ng-deep h1 {
854 font-size: 1.3rem;
855 border-bottom: 2px solid $grey-background-color;
856 padding-bottom: 15px;
857 margin-bottom: $sub-menu-margin-bottom;
858
859 > span > my-global-icon,
860 > my-global-icon {
861 @include margin-right(10px);
862 width: 24px;
863 height: 24px;
864 vertical-align: top;
865 }
866
867 .pt-badge {
868 @include margin-left(7px);
869
870 vertical-align: top;
871 }
872 }
873 }
874
875 @mixin play-icon ($width, $height) {
876 width: 0;
877 height: 0;
878
879 position: absolute;
880 left: 50%;
881 top: 50%;
882 transform: translate(-50%, -50%) scale(0.5);
883
884 border-top: #{math.div($height, 2)} solid transparent;
885 border-bottom: #{math.div($height, 2)} solid transparent;
886
887 border-left: $width solid rgba(255, 255, 255, 0.95);
888 }
889
890 @mixin on-small-main-col () {
891 :host-context(.main-col:not(.expanded)) {
892 @media screen and (max-width: $small-view + $menu-width) {
893 @content;
894 }
895 }
896
897 :host-context(.main-col.expanded) {
898 @media screen and (max-width: $small-view) {
899 @content;
900 }
901 }
902 }
903
904 @mixin on-mobile-main-col () {
905 :host-context(.main-col:not(.expanded)) {
906 @media screen and (max-width: $mobile-view + $menu-width) {
907 @content;
908 }
909 }
910
911 :host-context(.main-col.expanded) {
912 @media screen and (max-width: $mobile-view) {
913 @content;
914 }
915 }
916 }
917
918 @mixin margin ($arg1: null, $arg2: null, $arg3: null, $arg4: null) {
919 @if $arg2 == null and $arg3 == null and $arg4 == null {
920 @include margin-original($arg1, $arg1, $arg1, $arg1);
921 } @else if $arg3 == null and $arg4 == null {
922 @include margin-original($arg1, $arg2, $arg1, $arg2);
923 } @else if $arg4 == null {
924 @include margin-original($arg1, $arg2, $arg3, $arg2);
925 } @else {
926 @include margin-original($arg1, $arg2, $arg3, $arg4);
927 }
928 }
929
930 @mixin margin-original ($block-start, $inline-end, $block-end, $inline-start) {
931 @include margin-left($inline-start);
932 @include margin-right($inline-end);
933 @include margin-top($block-start);
934 @include margin-bottom($block-end);
935 }
936
937 @mixin margin-left ($value) {
938 @supports (margin-inline-start: $value) {
939 @include rfs($value, margin-inline-start);
940 }
941
942 @supports not (margin-inline-start: $value) {
943 @include rfs($value, margin-left);
944 }
945 }
946
947 @mixin margin-right ($value) {
948 @supports (margin-inline-end: $value) {
949 @include rfs($value, margin-inline-end);
950 }
951
952 @supports not (margin-inline-end: $value) {
953 @include rfs($value, margin-right);
954 }
955 }
956
957 @mixin padding-original ($block-start, $inline-end, $block-end, $inline-start) {
958 @include padding-left($inline-start);
959 @include padding-right($inline-end);
960 @include padding-top($block-start);
961 @include padding-bottom($block-end);
962 }
963
964
965 @mixin padding ($arg1: null, $arg2: null, $arg3: null, $arg4: null) {
966 @if $arg2 == null and $arg3 == null and $arg4 == null {
967 @include padding-original($arg1, $arg1, $arg1, $arg1);
968 } @else if $arg3 == null and $arg4 == null {
969 @include padding-original($arg1, $arg2, $arg1, $arg2);
970 } @else if $arg4 == null {
971 @include padding-original($arg1, $arg2, $arg3, $arg2);
972 } @else {
973 @include padding-original($arg1, $arg2, $arg3, $arg4);
974 }
975 }
976
977 @mixin padding-left ($value) {
978 @supports (padding-inline-start: $value) {
979 @include rfs($value, padding-inline-start);
980 }
981
982 @supports not (padding-inline-start: $value) {
983 @include rfs($value, padding-left);
984 }
985 }
986
987 @mixin padding-right ($value) {
988 @supports (padding-inline-end: $value) {
989 @include rfs($value, padding-inline-end);
990 }
991
992 @supports not (padding-inline-end: $value) {
993 @include rfs($value, padding-right);
994 }
995 }