// Nick's web site: SCSS colourmap helpers for automatic light/dark styles. // // Copyright © 2022 Nick Bowler // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // database of colour names $colourmap: (); // database of combination CSS properties that should be translated to // colour-only properties (e.g., border-top -> border-top-color). $_colourpropmap: ( border-top: border-top-color , border-bottom: border-bottom-color , border-left: border-left-color , border-right: border-right-color , border: border-color ); // Define a named set of colours. Pass keyword arguments with each keyword // being a colour name and the argument is a list of one or two colours. // // When two colours are specified, the first should be for "light" backgrounds // and the second for "dark". // // For example: // // @include defcolours($bg: white black, $fg: black white); @mixin defcolours($args...) { @each $colour, $list in keywords($args) { $colourmap: map-merge($colourmap, ($colour: $list)) !global; } } // Obtain the colour value for a previously-defined colour name. By // default, its primary (light) colour value is returned; this can be // changed with the $num keyword parameter. // // The $pre and $post keyword arguments may be used to supplement the // result with additional tokens either before or after the colour // value, respectively, as might be used for combined properties // such as border, outline, etc. @function getcolour($colour, $pre: (), $post: (), $num: 1) { @return join(append($pre, nth(map-get($colourmap, $colour), $num)), $post); } @mixin usecolour_dark_($prop, $colour, $pre: (), $post: ()) { @if (length(map-get($colourmap, $colour)) > 1) { $transprop: map-get($_colourpropmap, $prop); @if $transprop { #{$transprop}: getcolour($colour, $num: 2) } @else { #{$prop}: getcolour($colour, $pre, $post, 2); } } } // Sets the given CSS property to the specified colour name. The $pre // and $post keyword arguments may be used to supplement the property // value, as with the getcolour function. // // For two-value colours, the property is set using CSS variables to // adapt the colour based on the user's preference for a light or dark // background. The rules will fall back to the static (light) colour // if CSS variables are not supported. // // For example: // // @include usecolour(border, fg, $pre: solid 1px); @mixin usecolour($prop, $colour, $pre: (), $post: ()) { #{$prop}: getcolour($colour, $pre, $post); @at-root { @media (prefers-color-scheme: dark) { & { @include usecolour_dark_($prop, $colour, $pre, $post); } } } } // Convenience helper to assign multiple colour properties at once, for // the common case where the $pre and $post arguments to usecolour are // not required. // // Takes any number of keyword arguments with the keyword being the // property name and the value being the colour name. // // For example: // // @include usecolours($background-color: bg, $color: fg); @mixin usecolours($args...) { @each $prop, $colour in keywords($args) { #{$prop}: getcolour($colour); } @at-root { @media (prefers-color-scheme: dark) { & { @each $prop, $colour in keywords($args) { @include usecolour_dark_($prop, $colour); } } } } }