I'm developing a NuxtJS website and the pages/components can have either a generic design by default, either one that is customizable by client, and will be specified in the url.
Something alone the lines of:
http://localhost:3000/registration - For a generic page
http://localhost:3000/client-name/registration - Client specific page
To achieve that goal, I have a JSON configuration file per client (say client-name.json) that has this structure.
{
"some_configuration_property": {},
"another_configuration_property": {},
"design": {
"logoUrl": "/assets/client-name/logo.png",
"backgroundColor": "#000000",
"primaryColor": "#ffffff",
"secondaryColor": "#ffff00"
},
}
To start things, I implemented the routing system and I can successfully read each client's configuration based on the current route (inside the <script> tag of the Vue file of that route), inside the setup method (I use @nuxt/composition-api).
The problem that I'm facing now is to figure out how to pass these "design variables" into the <style> tag of my Vue file, which uses SCSS. The behaviour that I wanted to implement was to have a default design for a specific component/page, but that could be overridden by these "design variables" specific to each client.
Example:
// From the customizable component
.my-button {
color: (--button-color, teal);
}
// Styling from a parent component/view
// Had to create a selector with a style like <div> for superior specificity though, not so clean
v::deep {
div {
&.my-button {
--button-color: purple;
}
}
}
I've seen the /deep/ selector or ::v-deep pseudo selector but I don't think it's a very clean solution since it would be used a lot in the codebase. Styling component from parents would make the code hardly maintainable.
Another approach could be to pass a variable, classArray for instance, inside the setup method to dynamically bind CSS classes on the DOM elements. Although, it would be way too cumbersome to create a CSS class per client with the associated styles.
Like this:
<template>
<my-button :class="classArray"></my-button>
</template>
<script lang="ts">
import { defineComponent } from '@nuxtjs/composition-api'
export default defineComponent({
name: 'MyPage',
setup() {
const clientName = 'someClientName';
const classArray = [clientName]
return { classArray };
},
})
</script>
<style lang="scss" scoped>
.someClientName {
// some custom styles
}
</style>
What would be your approach in this situation?
Thanks for help!
If custom theme configuration needs to be loaded at runtime, this requires to use CSS variables (properties). They can be wrapped in SCSS functions and have default theme fallbacks:
// theme.scss
$primaryColor: #abc;
// $buttonColor: $primaryColor
@function primaryColor() {
@return #{var(--primary-color, $primaryColor)}
}
@function buttonColor() {
@return #{var(--button-color, primaryColor())}
}
Then primaryColor(), etc are used instead of direct use of $primaryColor, etc like it's done in regular SCSS theme:
// From the customizable component
.my-button {
color: buttonColor();
}
And custom theme can be applied on load to the entire document or a part of it (a hierarchy of components) that should be affected by custom theme:
const config = await loadClientConfig();
document.documentElement.style.setProperty(--primary-color, config.design.primaryColor)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With