I’ve been coding Home Base, an Übersicht widget, for the last couple of weeks, and it’s been really fun. With Übersicht, I can create macOS widgets using JSX, and, for me, customizing my computer’s desktop has been strangely rewarding.
It’s not perfect though; Übersicht doesn’t seem to
support CSS files. Instead, you style components using JavaScript
objects. Not my favourite way of doing things — I like to keep
styling definitions separate from code — but I got around the
problem by writing “CSS” in a JSON file (which I called
styles.json
) and importing it at runtime as a
JavaScript object.
Further along the widget’s development, I decided that I
wanted to support themes. I wanted to declare properties in a JSON
file and use them to determine styling choices (e.g. which font to
use). For readability, I wanted to handle all of the styling in
styles.json
, but how do you handle variables? Huh…
Let’s say we have the following code:
// themes.json
{
"red": {
"textColor": "#f00"
}
}
// styles.json
{
"emphasis": {}
}
import stylesJSON from "styles.json";
import themesJSON from "themes.json";
const theme = "red";
return (
<div style={stylesJSON.emphasis}>
Using the <q>{theme}</q> theme!
</div>
);
How can we style our div using the definitions in
themes.json
? Here’s my solution:
// themes.json
{
"red": {
"textColor": "#f00"
}
}
// styles.json
{
"emphasis": {
"color": "<textColor>"
}
}
import stylesJSON from "styles.json";
import themesJSON from "themes.json";
const makeStyles = (theme) => {
const pattern = /<[^>]*>/; // matches with <EXPRESSION>
const t = themesJSON[theme];
// Find all matches of `pattern` in `styleData` and replace them with their evaluated counterparts.
let s = JSON.stringify(stylesJSON);
while (s.match(pattern)) {
const match = s.match(pattern)[0];
s = s.replace(match, eval("t." + match.slice(1, -1)));
}
return JSON.parse(s);
};
const theme = "red";
const styles = makeStyles(theme);
return (
<div style={styles.emphasis}>
Using the <q>{theme}</q> theme!
</div>
);
Here’s a demo of my idea in action:
Pretty simple, right? It’s not the most efficient idea, but for my use case, it does the job well.
Could I have avoided the issue entirely by storing the styles in a
.js
file instead of a .json
file? Well,
yeah, but where’s the fun in that?
No comments yet.