summaryrefslogtreecommitdiff
path: root/addons/web/static/src/scss/utils.scss
blob: 0fcca801719fbcec4fb44c2ddd47c72e891ce81d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
///
/// This file regroups the odoo mixins. They are available in every asset bundle.
///

// ------------------------------------------------------------------
// Caret
// ------------------------------------------------------------------
@mixin utils-caret-boilerplate {
    content: "";
    display: inline-block;
    width: 0;
    height: 0;
    vertical-align: middle;
}

// ------------------------------------------------------------------
// Position absolute
// ------------------------------------------------------------------
@mixin o-position-absolute($top: auto, $right: auto, $bottom: auto, $left: auto) {
    position: absolute;
    top: $top;
    left: $left;
    bottom: $bottom;
    right: $right;
}

// ------------------------------------------------------------------
// Position sticky
// ------------------------------------------------------------------
@mixin o-position-sticky($top: auto, $right: auto, $bottom: auto, $left: auto) {
    position: -webkit-sticky;
    position: sticky;
    top: $top;
    left: $left;
    bottom: $bottom;
    right: $right;
}

// ------------------------------------------------------------------
// Text overflow
// ------------------------------------------------------------------
@mixin o-text-overflow($display: inline-block, $max-width: 100%) {
    display: $display;
    max-width: $max-width;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: top; // To update display context changed by overflow:hidden
}

// ------------------------------------------------------------------
// Hovering effects
// ------------------------------------------------------------------
@mixin o-hover-opacity($default-opacity: 0.5, $hover-opacity: 1) {
    opacity: $default-opacity;

    &:hover, &:focus, &.focus {
        opacity: $hover-opacity;
    }
}

//------------------------------------------------------------------------------
// Colors
//------------------------------------------------------------------------------

@function luma($color) {
    @return ((red($color) * .299) + (green($color) * .587) + (blue($color) * .114)) / 255 * 100%;
}
//
// Given two colors, returns the one which has the most constrast with another
// given color. Careful: if you want to find the text color which will suit the
// most on a given background color, you should use the 'color-yiq' function.
//
@function o-get-most-contrast($color, $c1, $c2, $background: #FFFFFF, $threshold: false, $cross-mix: true) {
    $background: if($background == null, #FFFFFF, $background);

    $real-color: mix(rgba($color, 1.0), $background, percentage(alpha($color)));
    $luma: luma($real-color);

    $cross-color: if($cross-mix, $real-color, $background);

    $real-c1: mix(rgba($c1, 1.0), $cross-color, percentage(alpha($c1)));
    $luma-c1: luma($real-c1);

    $real-c2: mix(rgba($c2, 1.0), $cross-color, percentage(alpha($c2)));
    $luma-c2: luma($real-c2);

    $-dark: if($luma-c1 <= $luma-c2, $c1, $c2);
    $-light: if($luma-c1 > $luma-c2, $c1, $c2);

    @if $threshold == false {
        // Automatic threshold: give a really small preference to light results
        // as bootstrap does by default (mainly by compatibility at the moment
        // this code is written)
        $threshold: ($luma-c1 + $luma-c2) * 0.515; // 150 / 145.63 * 0.5 would be the BS value
    }

    @return if($luma > $threshold, $-dark, $-light);
}

// Extend placeholder which adds a chess-like background below the color and
// image of an element to preview the transparency of that color and image.
// This is done thanks to both ::before and ::after elements so they must both
// be available.
%o-preview-alpha-background {
    position: relative;
    z-index: 0;

    &::before {
        content: "";
        @include o-position-absolute(0, 0, 0, 0);
        z-index: -1;
        background-image: url('/web/static/src/img/transparent.png');
        background-size: 10px auto;
        border-radius: inherit;
    }
    &::after {
        content: "";
        @include o-position-absolute(0, 0, 0, 0);
        z-index: -1;
        background: inherit; // Inherit all background properties
        border-radius: inherit;
    }
}

// ------------------------------------------------------------------
// Padding
// ------------------------------------------------------------------
@mixin o-webclient-padding($top: 0px, $right: $o-horizontal-padding, $bottom: 0px, $left: $o-horizontal-padding) {
    padding-top: $top;
    padding-right: $right;
    padding-bottom: $bottom;
    padding-left: $left;
}

// ------------------------------------------------------------------
// Caret
// ------------------------------------------------------------------
@mixin o-caret-down($caret-width: $caret-width) {
    @include utils-caret-boilerplate;
    border-bottom: 0;
    border-left: $caret-width solid transparent;
    border-right: $caret-width solid transparent;
    border-top: $caret-width solid;
    -moz-transform: scale(0.9999); // Smooth the caret on firefox
}
@mixin o-caret-up($caret-width: $caret-width) {
    @include utils-caret-boilerplate;
    border-bottom: $caret-width solid;
    border-left: $caret-width solid transparent;
    border-right: $caret-width solid transparent;
    border-top: 0;
    -moz-transform: scale(0.9999); // Smooth the caret on firefox
}
@mixin o-caret-left($caret-width: $caret-width) {
    @include utils-caret-boilerplate;
    border-bottom: $caret-width solid transparent;
    border-left: 0;
    border-right: $caret-width solid;
    border-top: $caret-width solid transparent;
    -moz-transform: scale(0.9999); // Smooth the caret on firefox
}
@mixin o-caret-right($caret-width: $caret-width) {
    @include utils-caret-boilerplate;
    border-bottom: $caret-width solid transparent;
    border-left: $caret-width solid;
    border-right: 0;
    border-top: $caret-width solid transparent;
    -moz-transform: scale(0.9999); // Smooth the caret on firefox
}

// ------------------------------------------------------------------
// Hovering effects
// ------------------------------------------------------------------
@mixin o-hover-text-color($default-color: $body-color, $hover-color: $link-color) {
    color: $default-color;

    &:hover, &:focus, &.focus {
        color: $hover-color;
    }
}

// ------------------------------------------------------------------
// Mixin to define variations for btn-links and muted btn-links
// ------------------------------------------------------------------
@mixin o-btn-link-variant($color, $color-active) {
    text-transform: none;
    @include o-hover-text-color($default-color: $color, $hover-color: $color-active);

    &, &:hover, &:focus, &:active, &.active {
        border-color: transparent;
        background-color: transparent;
    }

    &.text-muted, .text-muted {
        @include o-hover-opacity;
        @include o-hover-text-color($default-color: $text-muted, $hover-color: $color-active);
    }
}

// Odoo defines a limited Noto font-family for a small variety of unicode
// characters that are not necessary defined in the user system or even defined
// but not properly readable. This function allows to add this font family in a
// given font list.
//
// @param {list} $font - a list of font names ending with the generic one.
// @param {integer} [$index] - the position where to add the support font, if
//        not given, it will be placed before the generic one.
@function o-add-unicode-support-font($font, $index: false) {
    @if $index == false {
        $index: length($font);
    }

    $-with-support-font: ();
    @for $i from 1 through length($font) {
        @if $i == $index {
            $-with-support-font: append($-with-support-font, 'Odoo Unicode Support Noto', $separator: comma);
        }
        $-with-support-font: append($-with-support-font, nth($font, $i), $separator: comma);
    }

    @return $-with-support-font;
}

// Function to remove all null values of a map
@function o-map-omit($map) {
    $-map: ();
    @each $key, $value in $map {
        @if $value != null {
            $-map: map-merge($-map, (
                $key: $value,
            ));
        }
    }
    @return $-map;
}

// Function to swap two values in a list
@function o-swap($list, $i, $j) {
    $tmp: nth($list, $i);
    $list: set-nth($list, $i, nth($list, $j));
    @return set-nth($list, $j, $tmp);
}

// Function to get an element of a list with a default value in case the index
// is out-of-bounds; also return that value if the retrieved value is null.
@function o-safe-nth($list, $index, $default: null) {
    $value: if($index > 0 and $index <= length($list), nth($list, $index), null);
    @return if($value != null, $value, $default);
}

// Function to get an element of a map with a default value in case the key
// does not exist; also return that value if the retrieved value is null.
@function o-safe-get($map, $key, $default: null) {
    $value: map-get($map, $key);
    @return if($value != null, $value, $default);
}

// ------- Kanban grouped mixins -------
@mixin o-kanban-icon($base-opacity: 0.5) {
    display: block;
    text-align: center;
    color: $o-main-text-color;
    font-size: $font-size-sm;
    cursor: pointer;
    @include o-hover-opacity($base-opacity);
}
@mixin o-kanban-tag-color {
    @for $size from 1 through length($o-colors) {
        // Note: the first color is supposed to be invisible if there is a color
        // field but it is used as a default color when there is no color field
        &.o_tag_color_#{$size - 1} span {
            background-color: nth($o-colors, $size);
        }
    }
}
@mixin o-kanban-record-color {
    @for $size from 2 through length($o-colors) {
        // Note: the first color is not defined as it is the 'no color' for kanban
        .oe_kanban_color_#{$size - 1}::after {
            background-color: nth($o-colors, $size);
        }
    }
}
@mixin o-kanban-slim-col {
    position: relative;
    flex: 0 0 auto;
    margin: 0;
    padding: 0 floor($o-kanban-group-padding * 0.7);
    cursor: pointer;
}
@mixin o-kanban-header-title {
    display: flex;
    align-items: center;
    height: $o-kanban-header-title-height;
    line-height: 2.2;
    color: $headings-color;
}
@mixin o-kanban-v-title {
    @include o-position-absolute($o-kanban-inside-vgutter * 2, $left: floor(-$o-kanban-inside-vgutter * 1.2));
    transform-origin: left bottom 0;
    transform: rotate(90deg);
    overflow: visible;
    white-space: nowrap;
    font-size: 15px;
}

// ------- Kanban records mixins -------
@mixin o-kanban-record-title($font-size) {
    color: $headings-color;
    font-size: $font-size;
    font-weight: 500;
    margin-bottom: 0;
    margin-top: 0;
}
@mixin o-kanban-dropdown($padding-base: $o-kanban-inside-vgutter) {
    padding: $padding-base/2 $padding-base;
    border: none;
    border-left: 1px solid transparent;
    vertical-align: top;
    color: $body-color;

    &:hover {
        color: $headings-color;
    }
    &:focus, &:active, &:focus:active {
        outline: none;
    }
}
@mixin o-kanban-dropdown-open {
    position: relative;
    background: white;
    border-color: gray('400');
    z-index: $zindex-dropdown + 1;
}
@mixin o-kanban-dropdown-menu {
    @include o-position-absolute($right: -1px);
    margin-top: -1px;
    border-color: gray('400');
}
@mixin o-kanban-colorpicker {
    max-width: 150px;
    padding: 3px ($o-dropdown-hpadding - $o-kanban-inner-hmargin) 3px $o-dropdown-hpadding;

    > li {
        display: inline-block;
        margin: $o-kanban-inner-hmargin $o-kanban-inner-hmargin 0 0;
        border: 1px solid white;
        box-shadow: 0 0 0 1px gray('300');

        > a {
            display: block;

            &::after {
                content: "";
                display: block;
                width: 20px;
                height: 15px;
            }
        }

        // No Color
        &:first-child > a {
            position: relative;
            &::before {
                content: "";
                @include o-position-absolute(-2px, $left: 10px);
                display: block;
                width: 1px;
                height: 20px;
                transform: rotate(45deg);
                background-color: red;
            }
            &::after {
                background-color: white;
            }
        }
    }
}

// Emulate dropdown links
@mixin o-kanban-dashboard-dropdown-link($link-padding-gap: $o-dropdown-hpadding) {
    padding: 0;

    > a {
        margin: auto auto auto (-$link-padding-gap);
        padding: 3px $link-padding-gap;
        color: $body-color;
        display: block;

        &:hover {
            background-color: gray('300');
            color: $headings-color;
        }
    }
    &:last-child {
        margin-bottom: 5px;
    }
}

// No content helper
@mixin o-nocontent-empty {
    pointer-events: auto;
    max-width: 650px;
    margin: auto;
    padding: 15px;
    z-index: 1000;
    text-align: center;
    color: $o-tooltip-text-color;
    font-size: 115%;

    > p:first-of-type {
        margin-top: 0;
        color: $o-tooltip-title-text-color;
        font-weight: bold;
        font-size: 125%;
    }

    a {
        cursor: pointer;
    }
}

%o-nocontent-init-image {
    content: "";
    display: block;
    margin: auto;
    background-size: cover;
}

%o-nocontent-empty-document {
    @extend %o-nocontent-init-image;
    @include size(120px, 80px);
    margin-top: 30px;
    margin-bottom: 30px;
    background: transparent url(/web/static/src/img/empty_folder.svg) no-repeat center;
}