]> git.draconx.ca Git - homepage.git/blob - lib/colourmap.scss
Automatically adjust colour scheme for "dark mode".
[homepage.git] / lib / colourmap.scss
1 // Nick's web site: SCSS colourmap helpers for automatic light/dark styles.
2 //
3 // Copyright © 2022 Nick Bowler
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18 // database of colour names
19 $colourmap: ();
20
21 // database of combination CSS properties that should be translated to
22 // colour-only properties (e.g., border-top -> border-top-color).
23 $_colourpropmap:
24     ( border-top: border-top-color
25     , border-bottom: border-bottom-color
26     , border-left: border-left-color
27     , border-right: border-right-color
28     , border: border-color
29     );
30
31 // Define a named set of colours.  Pass keyword arguments with each keyword
32 // being a colour name and the argument is a list of one or two colours.
33 //
34 // When two colours are specified, the first should be for "light" backgrounds
35 // and the second for "dark".
36 //
37 // For example:
38 //
39 //   @include defcolours($bg: white black, $fg: black white);
40 @mixin defcolours($args...) {
41     :root {
42         @each $colour, $list in keywords($args) {
43             $colourmap: map-merge($colourmap, ($colour: $list)) !global;
44             @if length($list) > 1 {
45                 #{--colour- + $colour}: nth($list, 1);
46             }
47         }
48     }
49     @media (prefers-color-scheme: dark) {
50         :root {
51             @each $colour, $list in keywords($args) {
52                 @if length($list) > 1 {
53                     #{--colour- + $colour}: nth($list, 2);
54                 }
55             }
56         }
57     }
58 }
59
60 // For the given previously-defined colour name, returns its value from
61 // primary (light) colour scheme.
62 //
63 // The $pre and $post keyword arguments may be used to supplement the
64 // result with additional tokens either before or after the colour
65 // value, respectively, as might be used for combined properties
66 // such as border, outline, etc.
67 @function getcolour($colour, $pre: (), $post: ()) {
68     @return join(append($pre, nth(map-get($colourmap, $colour), 1)), $post);
69 }
70
71 @mixin usecolour_var_($prop, $colour, $pre: (), $post: ()) {
72     @if (length(map-get($colourmap, $colour)) > 1) {
73         $transprop: map-get($_colourpropmap, $prop);
74         @if $transprop {
75             #{$transprop}: var(--colour- + $colour)
76         } @else {
77             #{$prop}: join(append($pre, var(--colour- + $colour)), $post);
78         }
79     }
80 }
81
82 // Sets the given CSS property to the specified colour name.  The $pre
83 // and $post keyword arguments may be used to supplement the property
84 // value, as with the getcolour function.
85 //
86 // For two-value colours, the property is set using CSS variables to
87 // adapt the colour based on the user's preference for a light or dark
88 // background.  The rules will fall back to the static (light) colour
89 // if CSS variables are not supported.
90 //
91 // For example:
92 //
93 //   @include usecolour(border, fg, $pre: solid 1px);
94 @mixin usecolour($prop, $colour, $pre: (), $post: ()) {
95     #{$prop}: getcolour($colour, $pre, $post);
96     @at-root & { @include usecolour_var_($prop, $colour, $pre, $post); }
97 }
98
99 // Convenience helper to assign multiple colour properties at once, for
100 // the common case where the $pre and $post arguments to usecolour are
101 // not required.
102 //
103 // Takes any number of keyword arguments with the keyword being the
104 // property name and the value being the colour name.
105 //
106 // For example:
107 //
108 //   @include usecolours($background-color: bg, $color: fg);
109 @mixin usecolours($args...) {
110     @each $prop, $colour in keywords($args) {
111         #{$prop}: getcolour($colour);
112     }
113     @at-root & {
114         @each $prop, $colour in keywords($args) {
115             @include usecolour_var_($prop, $colour);
116         }
117     }
118 }