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
/// Functions
///--------------------------
/// Add alpha channel to a color
/// @access public
/// @param {Color} $color - color to work with
/// @param {Number} $percentage - percentage of `$color` opacity
/// @return {Color} $color
@function mix-alpha($color, $percentage) {
@return rgba($color, $percentage);
}
/// Add spacing length according to given unit
/// @access public
/// @param {Number} $num
/// @return {Size} $em
@function space-x($num) {
@return $num * $space-unit;
}
/// Calculate z-index value
/// @access public
/// @use {List} $z-indexes
/// @param {String} $key1 - key to retrieve for z-index matching
/// @param {String} $key2 - optiona, second key for deeper matching
/// @return {Number} z-index value
@function z-index($key1, $key2: null) {
$map: $z-indexes;
$found-index: null;
@if (map-has-key($map, $key1)) {
$found-index: index(map-keys($map), $key1);
@if ($key2) {
$map: map-get($map, $key1);
$found-index: index($map, $key2);
}
}
@return $found-index;
}
/// Mixins
///--------------------------
/// UX/UI rules regarding element that can be clicked and
/// others than <a/> tags
@mixin clickable() {
cursor: pointer;
&:focus { outline: 0; }
}
@mixin unclickable() {
cursor: default;
&:focus { outline: 0; }
}
@mixin unselectable() {
user-select: none;
}
@mixin disabled() {
cursor: not-allowed;
&:focus { outline: 0; }
}
@mixin gradient($primary, $secondary, $direction) {
background: linear-gradient($direction, $primary, $secondary);
}
/// Place contextualised element (&) at the root,
/// prefixed with left handed class
/// @access public
@mixin left-handed() {
@at-root .left-handed & {
@content;
}
}
/// Place contextualised element (&) at the root,
/// prefixed with right handed class
/// @access public
@mixin right-handed() {
@at-root .right-handed & {
@content;
}
}
/// Centering an element (you'll have to change the position
/// of the element though)
@mixin centered() {
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
/// Mixin from "bootstrap v4"
/// @link https://getbootstrap.com/docs/4.3/utilities/clearfix/
@mixin clearfix() {
&::after {
display: block;
content: "";
clear: both;
}
}
/// Reverse an element
@mixin reversed() {
transform: scaleX(-1);
}
/// Add led effect with the input color
/// @param {Color} $color
@mixin led($color) {
color: $color;
text-shadow: 0 0 4px brighten($color, 90);
}
@mixin light-bulb($color) {
color: $color;
text-shadow: 0 0 4px;
}
/// Extend element to fit all four positions
/// @param {value} value [default: 0]
@mixin fit-positions($value: 0) {
top: $value;
right: $value;
bottom: $value;
left: $value;
}
/// Add a basic ripple effect based on CSS pseudo class
///
/// * Not as qualitative as a dedicated ripple HTML element
/// * One design flaw on "mouseover" where the transition will be the one
/// one the ripple layer (instead of the first classic CTA layer)
/// * Offers a YAGNI solution when only CSS is available)
///
/// @param {Color} $background-color
/// @param {Color} $wave-color default is a lighten version of bg color
@mixin ripple-effect(
$background-color,
$wave-color: lighten($background-color, 15%)
) {
position: relative;
/// First layer: classic CTA hover effect
&::before {
@include fit-positions;
content: "";
position: absolute;
z-index: 1;
background-color: $background-color;
transition: background 0.15s ease-in-out;
}
&:hover::before {
background-color: $wave-color;
}
/// Second layer: more slower ripple effect
&::after {
@include fit-positions;
content: "";
position: absolute;
z-index: 2;
background-position: center;
background-color: transparent;
transition: background 0.6s ease-out;
}
&:hover::after {
background:
$wave-color
radial-gradient(
circle,
transparent 1%,
$wave-color 1%
)
center/15000%;
}
&:active::after {
background-color: $background-color;
background-size: 100%;
transition: background 0s;
}
/// Other layers: container contents
& > * {
z-index: 3;
}
}
/// Add a virtual space on pure empty tag
/// This will allow to set a width or height rules
@mixin virtual-content() {
content: "\200B";
}
@mixin virtual-space() {
&::after {
@include virtual-content();
}
}
/// Hidden vertical scrollbar
@mixin hidden-scrollbar() {
scrollbar-width: none;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
}