aboutsummaryrefslogtreecommitdiffstats
path: root/src/_harmony.scss
blob: 839036cd7a6233c1f55875ece0abfa06005869d9 (plain) (blame)
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
////
/// Harmony.
///
/// Contains functions to make a design appear more harmonic.
///
/// @group Harmony
///
/// @access public
////

@use 'sass:math';
@use './functions';
@use './responsive';

/// 
/// Adjust a value to a modular scale.
///
/// For a more sophisticated solution, check out [modularscale-sass](https://github.com/modularscale/modularscale-sass).
///
/// @link http://alistapart.com/article/more-meaningful-typography An article about modular scales by Tim Brown
///
/// @param {number}        $times - Number of iterations. If positive, $base will be multiplied with $ratio. If negative, $base will be divided by $ratio.
/// @param {number | list} $base  - Single base value or, for a multi-stranded modular scale, a list of base values
/// @param {number}        $ratio - Ratio
///
/// @return {number}
///
@function modular-scale($times, $base, $ratio) {
    @if type-of($base) == number {
        @return $base * math.pow($ratio, $times);
    }

    $main-base:  nth($base, 1);
    $norm-bases: ();

    @each $b in functions.list-slice($base, 2) {
        @if $b > $main-base {
            @while $b > $main-base {
                $b: math.div($b, $ratio);
            }
            $b: $b * $ratio;
        } @else if $b < $main-base {
            @while $b < $main-base {
                $b: $b * $ratio;
            }
        }

        $norm-bases: append($norm-bases, $b);
    }

    $all-bases: append($norm-bases, $main-base);
    $all-bases: functions.quicksort($all-bases);

    $base-index: $times % length($all-bases) + 1;
    $exp:        math.floor(math.div($times, length($all-bases)));

    @return nth($all-bases, $base-index) * math.pow($ratio, $exp);
}

///
/// Combine responsive properties with modular scales to achieve responsive modular scales.
///
/// @param {string | list} $props          - Property or list of properties to set
/// @param {number}        $times          - Number of iterations. See modular-scale for more information.
/// @param {number}        $responsive-map - A map with keys = viewports and values = modular scales
/// @param {bool}          $fluid [true]   - If enabled, property values will smoothly transition from one viewport to the next
///
/// @see {function} modular-scale
///
/// @example scss - Responsive font sizes between 2 viewports based on modular scales
///   $ms: (
///     320px: (1rem 2rem, 1.1),
///     640px: (1rem 2rem, 1.2)
///   );
///
///   h1 {
///     @include responsive-modular-scale(font-size, 3, $ms);
///   }
///
///   h2 {
///     @include responsive-modular-scale(font-size, 2, $ms);
///   }
///
///   h3 {
///     @include responsive-modular-scale(font-size, 1, $ms);
///   }
///
@mixin responsive-modular-scale($props, $times, $responsive-map, $fluid: true) {
    $new-map: ();

    @each $key, $value in $responsive-map {
        $new-map: map-merge($new-map, (
                $key: modular-scale($times, $value...)
        ));
    }

    @include responsive.property($props, $new-map, $fluid);
}