end
compile '/**/*.scss' do
- filter :sass, syntax: :scss
+ filter :sass, syntax: :scss, load_paths: ["."]
filter :css_source, uribase: \
"https://git.draconx.ca/gitweb/homepage.git/blob/" +
@item[:gitrev] + ":"
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-// colour definitions
-$backgroundcolour: #ffffff;
-$foregroundcolour: #000000;
+@import "lib/colourmap.scss";
-$linkdefaultcolour: #0000cd;
-$linkactivecolour: #ff0000;
-$linkvisitedcolour: #800080;
+@include defcolours
+ ( $background: #ffffff #000000
+ , $foreground: #000000 #ffffff
-$ruledefaultcolour: #d3d3d3;
-$rulestrongcolour: #696969;
+ , $linkdefault: #0000cd #a3aaff
+ , $linkactive: #ff0000
+ , $linkvisited: #800080 #e493f7
+ , $focusring: #628cb2
-$annotationcolour: #708090;
+ , $annotation: #708090
+ , $tableshade: #f5f5f5 #101010
-$tableshadecolour: #f5f5f5;
-
-$focusringcolour: #628cb2;
+ , $ruledefault: #d3d3d3 #494949
+ , $rulestrong: #696969 #939393
+ );
@mixin header_size($maxwidth, $fontsize) {
font-size: $fontsize;
}
body {
- background-color: $backgroundcolour;
- color: $foregroundcolour;
font-family: sans-serif;
margin: 1em;
+
+ @include usecolours
+ ( $background-color: background
+ , $color: foreground
+ );
}
-a:link { color: $linkdefaultcolour; border-color: $linkdefaultcolour; }
-a:visited { color: $linkvisitedcolour; border-color: $linkvisitedcolour; }
-a:active { color: $linkactivecolour; border-color: $linkactivecolour; }
+a:link {
+ @include usecolours($color: linkdefault, $border-color: linkdefault);
+}
+a:visited {
+ @include usecolours($color: linkvisited, $border-color: linkvisited);
+}
+a:active {
+ @include usecolours($color: linkactive, $border-color: linkactive);
+}
@supports (outline-style: auto) {
a:link { border-width: 0; }
- a:focus { outline: auto $focusringcolour; }
+ a:focus { @include usecolour(outline, focusring, auto); }
li, td, dt { &>a:link { border: solid 1px transparent; } }
}
}
small {
- color: $foregroundcolour;
+ @include usecolours($color: foreground);
text-align: justify;
@media (max-width: 24em) { text-align: left; }
padding: 0.5ex;
clear: both;
margin: 0.5em 0;
border: 0;
- border-top: 1px solid $ruledefaultcolour;
+ @include usecolour(border-top, ruledefault, 1px solid);
}
kbd {
}
.permalink {
+ @include usecolours($color: annotation);
font-size: small;
- color: $annotationcolour;
a:link, a:visited { color: inherit; }
+ a:active { @include usecolours($color: linkactive); }
@media not screen { visibility: hidden; }
}
// General table styles.
table {
- border: 1px solid $ruledefaultcolour;
+ @include usecolour(border-top, ruledefault, 1px solid);
border-collapse: collapse;
width: 100%;
}
margin: 0;
}
-thead>tr, tbody>tr { border: solid $ruledefaultcolour; }
-th, thead>tr { border-bottom: 1px solid $rulestrongcolour; }
-tbody+tbody { border-bottom: 1px solid $ruledefaultcolour; }
+thead>tr, tbody>tr { @include usecolour(border, ruledefault, solid); }
+th, thead>tr { @include usecolour(border-bottom, rulestrong, 1px solid); }
+tbody+tbody { @include usecolour(border-bottom, ruledefault, 1px solid); }
*>table, *>th { border: none; }
thead>tr { border-width: 1px; }
tbody>tr { border-width: 0 1px; }
-td + td { box-shadow: -1px 0 $backgroundcolour; }
+td + td {
+ @include usecolour(box-shadow, background, -1px 0);
+}
tbody>tr {
- &:nth-of-type(even) { background-color: $tableshadecolour; }
- &:last-child { border-bottom: solid 1px $ruledefaultcolour; }
+ &:nth-of-type(even) { @include usecolours($background-color: tableshade); }
+ &:last-child { @include usecolour(border-bottom, ruledefault, solid 1px); }
}
// Specific table styles
#{"input.clicky-#{$col+$focuslabel}"}>span:first-child
, #{"input.clicky-#{$col}-rev#{$focuslabel}"} .svg
{
- border-color: $foregroundcolour;
+ @include usecolours($border-color: foreground);
@at-root { @supports (outline-style: auto) { & {
+ @include usecolour(outline, focusring, auto);
border-color: transparent;
- outline: auto $focusringcolour;
}}}
}
}
padding-right: 2px;
}
- &:active { color: $linkactivecolour; }
+ &:active { @include usecolours($color: linkactive); }
&:first-child:active>span, &~label:active>.svg {
- border-color: $linkactivecolour;
+ @include usecolours($border-color: linkactive);
@at-root { @supports (outline-style: auto) { & {
+ @include usecolour(outline, focusring, auto);
border-color: transparent;
- outline: auto $focusringcolour;
}}}
}
}
}
-#footer p { color: $annotationcolour; }
+#footer p { @include usecolours($color: annotation); }
#article-info p { font-style: italic; }
.wbr:after { content: "\200b"; }
#sitetitle * { float: none; }
#footer { padding: 0 1em; }
}
+
+// page-specific dark mode styles
+@media (min-width: 35em) {
+ #page_weblog_responsive_tables {
+ @each $tN in t6 t7 t8 {
+ ##{$tN}>tbody>tr.#{$tN}-split {
+ @include usecolour_var_(border-bottom, ruledefault);
+
+ &:nth-of-type(odd) ~ tr:nth-of-type(odd) {
+ @include usecolour_var_(background-color, tableshade);
+ }
+ }
+ }
+ }
+}
#t6>thead, #t6>tbody { display: grid; }
#t6>tbody>tr.t6-split { border-bottom: 1px solid <%=
- scss_get_var(:ruledefaultcolour) %>; }
+ scss_get_colour(:ruledefault) %>; }
#t6>tbody>tr.t6-split:nth-of-type(odd) ~ tr:nth-of-type(even) {
background-color: initial;
}
#t6>tbody>tr.t6-split:nth-of-type(odd) ~ tr:nth-of-type(odd) {
- background-color: <%= scss_get_var(:tableshadecolour) %>;
+ background-color: <%= scss_get_colour(:tableshade) %>;
}
}
}
#t7>thead, #t7>tbody { display: grid; }
#t7>tbody>tr.t7-split { border-bottom: 1px solid <%=
- scss_get_var(:ruledefaultcolour) %>; }
+ scss_get_colour(:ruledefault) %>; }
#t7>tbody>tr.t7-split:nth-of-type(odd) ~ tr:nth-of-type(even) {
background-color: initial;
}
#t7>tbody>tr.t7-split:nth-of-type(odd) ~ tr:nth-of-type(odd) {
- background-color: <%= scss_get_var(:tableshadecolour) %>;
+ background-color: <%= scss_get_colour(:tableshade) %>;
}
}
}
#t8>thead, #t8>tbody { display: grid; }
#t8>tbody>tr.t8-split { border-bottom: 1px solid <%=
- scss_get_var(:ruledefaultcolour) %>; }
+ scss_get_colour(:ruledefault) %>; }
#t8>tbody>tr.t8-split:nth-of-type(odd) ~ tr:nth-of-type(even) {
background-color: initial;
}
#t8>tbody>tr.t8-split:nth-of-type(odd) ~ tr:nth-of-type(odd) {
- background-color: <%= scss_get_var(:tableshadecolour) %>;
+ background-color: <%= scss_get_colour(:tableshade) %>;
}
}
<!--
Nick's web site: Intermediate document structure.
- Copyright © 2016-2020 Nick Bowler
+ Copyright © 2016-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
" <published>%Y-%m-%d</published>\n" if @item[:published]
%> </article>
<% end
-%> <html xmlns="<%= Xmlns['xhtml'] %>">
+%> <html xmlns="<%= Xmlns['xhtml'] %>" id="<%=
+ "page" + @item.identifier.without_ext.gsub(/[^[:alnum:]]/, "_")
+%>">
<% if !doc_header then
%> <h1><%= @item.fetch(:header, @item[:title]) %></h1>
<% end %><%= doc_str
--- /dev/null
+// 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 <https://www.gnu.org/licenses/>.
+
+// 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...) {
+ :root {
+ @each $colour, $list in keywords($args) {
+ $colourmap: map-merge($colourmap, ($colour: $list)) !global;
+ @if length($list) > 1 {
+ #{--colour- + $colour}: nth($list, 1);
+ }
+ }
+ }
+ @media (prefers-color-scheme: dark) {
+ :root {
+ @each $colour, $list in keywords($args) {
+ @if length($list) > 1 {
+ #{--colour- + $colour}: nth($list, 2);
+ }
+ }
+ }
+ }
+}
+
+// For the given previously-defined colour name, returns its value from
+// primary (light) colour scheme.
+//
+// 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: ()) {
+ @return join(append($pre, nth(map-get($colourmap, $colour), 1)), $post);
+}
+
+@mixin usecolour_var_($prop, $colour, $pre: (), $post: ()) {
+ @if (length(map-get($colourmap, $colour)) > 1) {
+ $transprop: map-get($_colourpropmap, $prop);
+ @if $transprop {
+ #{$transprop}: var(--colour- + $colour)
+ } @else {
+ #{$prop}: join(append($pre, var(--colour- + $colour)), $post);
+ }
+ }
+}
+
+// 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 & { @include usecolour_var_($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 & {
+ @each $prop, $colour in keywords($args) {
+ @include usecolour_var_($prop, $colour);
+ }
+ }
+}
# Nick's web site: Helper to retrieve global style variables in ruby.
#
-# Copyright © 2020 Nick Bowler
+# Copyright © 2020, 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
x = new(nil)
x.send(:visit, root)
result = x.instance_variable_get(:@globals)
- if name.nil?
- return result.freeze
- else
- return result[name]
- end
+ return result.freeze if name.nil?
+
+ x.send(:rubify_result, result[name])
end
protected
def visit_variable(node)
super
-
+
x = @environment.global_env.var(node.name)
- if !x.nil?
- @globals[node.name] = x
+ @globals[node.name] = x unless x.nil?
+ end
+
+ # Convert SASS maps and lists to ruby equivalents that are actually usable.
+ def rubify_result(val)
+ case val
+ when Sass::Script::Value::Map
+ val.to_h.each_with_object({}) do |(k, v), h|
+ h[k.to_s.to_sym] = rubify_result(v)
+ end
+ when Sass::Script::Value::List
+ val.to_a.map { |v| rubify_result(v) }
+ else
+ val
end
end
end
def scss_get_var(variable, item = @items["/style.scss"])
- engine = Sass::Engine.for_file(item.raw_filename, { :syntax => :scss })
+ engine = Sass::Engine.for_file(item.raw_filename, {
+ :syntax => :scss,
+ :load_paths => ["."],
+ })
return GetSCSSGlobals.visit(engine.to_tree, variable)
end
+
+def scss_get_colour(colour, index = 0, item = @items["/style.scss"])
+ cmap = scss_get_var(:colourmap, item);
+ [cmap[colour]].flatten[index]
+end