Qtheme main goal is to provide easy way to manage themes in your app (JS/TS/any framework). It's not a CSS framework, it's just a library that will help you to manage themes.
But... Qtheme can generate CSS for you, based on theme atoms, so you don't have to write it by yourself. It's optional.
To sum up, Qtheme lets you:
- Create infinite number of themes
- Switch between them easily
- Set common theme atoms for all themes
- Initialize already chosen theme on app start
- Generate CSS classes for you, so you don't have to write it by yourself
Declare themes
First of all, you need to declare your themes. Each theme should have name and atoms.
It is recommended to create a separate folder /themes with separate file for each theme.
import {Theme} from '@quak.lib/qtheme'
const darkTheme: Theme = {
name: 'dark',
atoms: [
// Will not generate any CSS class, only variable --primary: dodgerblue
['primary', 'dodgerblue'],
// Will generate CSS like: .bg-color { background-color: var(--bg-color) }
['bg-color', 'background-color:hsl(0, 100%, 0%)'],
['text-color', 'color:#fff'],
['text-primary', 'color:var(--primary)']
]
};
const lightTheme: Theme = {
name: 'light',
atoms: [
['primary', 'dodgerblue'],
['bg-color', 'background-color:hsl(0, 0%, 100%)'],
['text-color', 'color:black'],
['text-primary', 'color:var(--primary)']
]
};
Default theme atoms
Without default values in CSS, if you want to use var(--your-atom) in your CSS it will work, but you will get an error in IDE, because IDE doesn't know about your theme atoms.
.your-class {
/* error in IDE, underlined --bg-color */
background: var(--bg-color);
}
To prevent such a behavior use :root in CSS to initialize theme atoms, it's optional, will work without it, but... you will get an error in IDE.
/* Put here your default theme variables */
:root {
--bg-color: hsl(0, 100%, 0%);
/* ... */
}
Get theme
Qtheme saves theme in localStorage, you can initialize theme with it on app start, or get it later.
import {Qtheme, Theme} from '@quak.lib/qtheme'
const currentTheme: Theme | null = Qtheme.getTheme();
// Optional, to change default localStorage key, defaults to 'Qtheme'
const currentTheme: Theme | null = Qtheme.getTheme('yourThemeLocalStorageKey');
Initialize theme
You can utilize that Qtheme will save your theme in localStorage, you can initialize it on app start.
import {Qtheme, Theme} from '@quak.lib/qtheme'
import {lightTheme, darkTheme} from 'path/to/your/themes'
// Simply load from localStorage else init with darkTheme and commonAtoms
Qtheme.init(darkTheme, {commonAtoms}); // commonAtoms are optional
// Or do it manually
const savedTheme: Theme | null = Qtheme.getTheme();
if (savedTheme) {
Qtheme.setTheme(savedTheme);
} else {
Qtheme.setTheme(darkTheme);
}
// Or with your custom localStorage key, defaults to 'Qtheme'
const savedTheme: Theme | null = Qtheme.getTheme('yourThemeLocalStorageKey');
if (savedTheme) {
Qtheme.setTheme(savedTheme, {token: 'yourThemeLocalStorageKey'});
} else {
Qtheme.setTheme(darkTheme, {token: 'yourThemeLocalStorageKey'});
}
Change theme
To change theme call Qtheme.setTheme with new theme. You can specify your custom localStorage key, defaults to 'Qtheme'.
import {Qtheme} from '@quak.lib/qtheme'
import {lightTheme} from 'path/to/your/themes'
Qtheme.setTheme(lightTheme);
// Or with your custom localStorage key, defaults to 'Qtheme'
Qtheme.setTheme(lightTheme, {token: 'yourThemeLocalStorageKey'});
Use theme in HTML
Use your theme atoms in HTML, it will generate CSS classes for you.
<div class="bg-color">
<h1 class="text-primary">Hello world!</h1>
<p class="text-color">This is regular text color</p>
</div>
Common theme atoms
You probably want to use some common theme atoms in all your themes, like compound atoms: btn, btn-primary. You can set them with Qtheme.setCommonAtoms and use them in your themes.
import {Qtheme, ThemeAtom} from '@quak.lib/qtheme'
import {btn, btnPrimary, btnPrimary, btnPrimaryHover} from '/path/to/your/compoundAtoms'
const atoms: ThemeAtom[] = [
['btn', btn],
['btn:hover', btnHover],
['btn-primary', btnPrimary],
['btn-primary:hover', btnPrimaryHover]
];
Qtheme.setCommonAtoms(atoms);
// or with your custom localStorage key, defaults to 'Qtheme-common'
Qtheme.setCommonAtoms(atoms, {commonToken: 'yourCustomCommonThemeAtomsToken'});
Compound atoms
You can use compound atoms to create more complex atoms. Compound atoms are just objects of css property: value pairs.
<button class="btn">Click me</button>
<button class="btn-primary">Click me</button>
import {Qtheme, ThemeAtom, CSSProps} from '@quak.lib/qtheme'
const btn: CSSProps = {
fontSize: '1rem',
color: 'var(--primary)',
backgroundColor: 'var(--primary-inner)',
padding: '0.5rem 1rem',
border: '1.5px solid var(--primary)',
outlineColor: 'var(--primary-focus)',
borderRadius: '0.25rem',
}
const btnPrimary: CSSProps = {
...btn,
backgroundColor: 'var(--primary-focus)',
color: 'var(--primary-content)'
}
const btnHover: CSSProps = {
backgroundColor: 'var(--primary)',
color: 'var(--primary-content)',
cursor: 'pointer'
}
const btnActive: CSSProps = {
borderStyle: 'inset',
borderWidth: '1.5px',
}
const commonAtoms: ThemeAtom[] = [
['btn', btn],
['btn:hover', btnHover],
['btn:active', btnActive],
['btn-primary', btnPrimary],
['btn-primary:hover', btnHover],
['btn-primary:active', btnActive],
]
// You need to init these atoms before you can use them in your html
Qtheme.setCommonAtoms(commonAtoms);
// or
Qtheme.setTheme({name: 'theme', atoms: [...darkThemeAtoms, ...commonAtoms]});
// or load already saved from localStorage else commonAtoms will be used
Qtheme.init({name: 'theme', atoms: darkThemeAtoms}, {commonAtoms: commonAtoms});