Working on a simple static site
I spent the evening working on a very simple static site. First thing I did was copy the CSS from this blog over to that site. I really like the way the CSS variables are organized on this blog.
One thing I don’t like is organizing CSS though. I generally try to utilize element styles, utility classes and classes for specific use cases. Take a site navigation for example. At the most basic level, the body
element gets its own, default styles, to set up the font family, size and weight. Next you want to maybe have a horizontal list of navigation entries on larger screens and a vertical list on smaller screens. These could be done via .cluster
and .stack
classes (taken from one of my favorite books on anything computer, Every Layout). The problem with this is that you can’t apply CSS classes based on media queries. You can only apply CSS rules. You can either have two different chunks of HTML, show and hide them with media queries, and utilize these layout primitives (stack, cluster, …) or you inline the respective rules into a feature class. At least that’s what I call them. These are classes for art direction, where you have one-off CSS rules that aren’t generally useful.
Deciding what goes in a feature class, when you should favor a single chunk of HTML with a feature class or multiple chunks with utility classes and media queries – these are hard decisions to make. I find it much easier to organize actual code than CSS.
I like to believe that I’ve improved quite a bit at this over the years. My rules of thumb are:
- try to rely on feature classes as little as possible
- try to use layout primitives as much as possible
- when none of the above work, try a utility class instead (
text-align:center
)
- if all else fails, feature class it is
Bitten by complicated FP once again
October 10, 2024
Before falling asleep I had some ideas for this website. I want to add a dark mode, use the colors from my Neovim theme and also make some layout changes. I thought using the colors from my theme would be straight forward, since I can just generate some CSS variables as an additional output. There’s a new-ish light-dark
CSS function that I can use and generate CSS like this:
--color-yellow-fg: light-dark(#000, #fff);
Except that I can’t. The way my theme works is that it all starts with a configuration table that has two entries, for the light and the dark colors. Each variant is then passed to a make_themes
function, which is a mini pipeline that outputs the different light or dark themes (Alacritty, Fish, …). The key realization here is that the pipeline only ever has access to light or dark colors, but never both. Now go back and look at the light-dark
function. Yes, it needs both.
This is yet another case of making a system unnecessarily constrained. I’m so often reminded of Rich Hickey these days. If I had just dumped all colors into a map that has the complete “theme context”, and passed that around, it would be much simpler to make modifications now. What makes matters worse is that I wrote all of this in a style that resembles functional programming more than idiomatic Lua. There’s lots of mapkv(fn, merge(tableA, tableB))
. This also makes it hard to modify my own code, which I wrote mere months ago.
I guess I’ll start by solving the immediate problem and somehow make the full theme context available everywhere. Next, I’ll untangle the FP stuff.
I stepped away from the computer for a bit which brought me some much needed mental clarity. In the end it wasn’t as difficult as I thought. In fact, a pretty sizeable Lua refactor worked on first try, which is really rare for me, when programming in a dynamic language like Lua. I created a context table that has both light and dark and passed this to the theme functions, which now return a table that has a light and a dark key. I tried relying less on FP constructs but the code is still a bit of a mess. At least I managed to always keep the code in a working state. The last hurdle is that the string producting template functions are all called with a huge table that has the key/value color pairs from all themes in it. The idea behind this is that one theme can reference colors from another. This is actually one of the two key ideas behind this theme. Why is this annoying now? I want to create one CSS variable for every base color value my theme has (light.sucess.fg
, dark.success.fg
, …). The way this works in all themes so far is that you create a template string:
--color-light-success-fg: light-dark(${light-success-fg}, ${dark-success-fg})
This feels tedious though. Can’t I just generate those lines automatically based on the variable names? The problem here is that I have this huge blob of stuff and there’s currently no way to differentiate which slice of keys comes from which theme. It would be nice, in retrospect, if that big table worked like this
local colors = {
nvim = {
Normal = {},
},
css = {
LightSuccess = {}
}
}
instead of
local colors = {
Normal = {},
LightSuccess = {},
}
The pragmatic thing for now is to stick with the repetitive string templating.
Dark mode for terminal users
I firmly believe that you should use light mode when the ambient lighting is bright. As far as I know, science agrees with that, since dark text on a white background is easier to read than the opposite.
But after the sun has set and you’ve dimmed all the lights, staring at a bright screen seems wrong and it looks out of place when the rest of your system switches to dark mode.
For the longest time I’ve therefore wanted to have the automatic dark/light mode switching in my terminal environment, which consists of Alacritty, tmux, Fish and Neovim (tmux doesn’t define any color values of its own, so we can ignore it).
I finally got around to spending some time on this not so tricky problem and I’d say I’m 85% there. I use my own color theme which exports config files for, among other things, all three programs listed above. And all config files are available in a dark and a light mode. Meaning, in Neovim I can simply switch to the dark version with :color yui_dark
. Since Neovim has a nice client/server architecture I can also do this remotely:
:let g:lightline.colorscheme = "yui_dark" | colorscheme yui_dark | call lightline#init() | call lightline#colorscheme() | call lightline#update()<CR>
Alacritty also has a nice API for changing config values from the shell. You can read more about it under man alacritty-msg
(and man 5 alacritty
for the config values) but the gist is alacritty msg config -w -1 'colors.cursor.background="#CCCCCC"'
.
Lastly, for configuring the Fish shell syntax colors you use shell commands anyway, so the exported “config” is a Fish file that I can call whenever I want. The file has commands like this:
set fish_color_match eae9e9
set fish_color_selection --background=474355
set fish_color_search_match --background=4f4b5f
...
In other words: I now have shell commands for remotely changing Alacritty, Fish and Neovim from light to dark mode and vice versa. The “only” thing left to do is to find a way of running either of the two variants when the system switches themes.
Why is `O(log n) + O(log n) = O(log n)`
I was thinking about this recently while doing some Leetcode binary search problems. For this particular problem I split it up into two sub problems, each of which used binary search.
This Stack Overflow answer explains it nicely. Constant, multiplicative factors don’t matter much for Big O notation. So the sub problems can also be thought of as O(2 * log n)
, where the constant factor of 2 doesn’t matter.
During this exercise I also came across a cool graphing tool called Desmos which could be very handy for visualizing and intuitively understanding some of these concepts.