The UI is too white. A good app should have a theme switching feature. A high contrast theme is necessary for accessibility.
Though I only want the dark theme now.
There are a few ways to implement theme switching. I like CSS approaches because they’re usually simpler. But since we’re using Vue, I want to make use of it.
Using Vue
The current UI can be considered as the light theme. For the dark theme, we basically need a dark background and white text.
Actually, we’ll need several dark backgrounds. At least two in the current situation: one for the page background and one for the cards. Thanks to Bulma, this can be done easily by replacing CSS classes in a few places.
The (kind of) “before” and “after” of the HTML:
<body class="has-background-white-ter">
...
<div class="card has-background-white-bis">
...
</div>
...
</body>
<body class="has-background-dark">
...
<div class="card has-background-grey-dark has-text-light">
...
<p class="card-header-title has-text-light">
...
</p>
...
</div>
...
</body>
The buttons and input fields can be easily changed since Bulma classes were used.
So, we have a handful of classes for each theme. Now all we need is something that can set the class names based on the value of a certain variable.
Inside App.vue, we can add an isDarkTheme property that will have false as the default value. Then the classes can be added based on its value:
<div class="card"
:class="'has-background-' + (isDarkTheme ? 'white-bis' : 'grey-dark')"
:class="{ 'has-text-light' : isDarkTheme }"
>
...
<p class="card-header-title" :class="{ 'has-text-light' : isDarkTheme }">
...
</p>
...
</div>
You should’ve noticed a problem already. The <body> tag is out of reach of the App component.
We can solve that by removing the background color from <body> and adding it to the element immediately inside the App component’s template. Some other CSS modifications will be necessary.
Now if we add a checkbox connected to isDarkTheme with a v-model attribute, themes can be easily switched by simply checking and unchecking it.
Except not inside child components.
isDarkTheme is a property of App and doesn’t automatically get passed to child components. So, they have no way of knowing when the checkbox is checked or unchecked. This can be solved by passing isDarkTheme as a prop to all child components, and they’ll pass it to all their child components and so on until the end of the world.
Seems a lot of work.
(I know there are lots of theme switching methods crowding the street out there. But I want to try to solve the problem myself and see what I come up with, what problems I face, etc.)
Back to CSS
The CSS way I’ve been using is rather plain. And it limits the HTML structure a bit.
It’s done using a checkbox and the CSS adjacent sibling combinator to switch styles. We add a checkbox before the superdupercontainer that contains everything of the webpage. Then, when the checkbox is checked, a certain type of style is applied to the descendants of the container; and when it’s unchecked, a different type of style is applied to the descendants.
In Mantle’s case, it’d look like this:
<body>
<input type="checkbox" id="theme-switcher">
<div id="app">
...
</div>
</body>
.card {
background-color: white;
}
#theme-switcher[checked] + #app .card {
background-color: black;
}
But this means lots of selectors must have #theme-switcher[checked] + #app added in front of them, which looks bad.
And, more importantly, we lose the ease of using Bulma’s classes. When using the JS approach, we were just changing the class names and everything would look nicely different. Here, we’ll have to manually write the CSS code. Then what’s the point of Bulma?
So, this is a no-go.
Now what?
If we want to use Bulma, seems like we must use Vue. Can we bypass the eternal prop-passing somehow?
To be pursued later
(I don’t want dark theme now anymore. All the colors I used were set thinking of light backgrounds. Every little badge is waging wars with the dark colors now. I need to pick some colors first, and that’s a job for another day.
Goes to show why you should plan first (even a little).)
Check out Mantle on GitHub here