Skip to content

Commit e91ec88

Browse files
erbilnasgkhnakntyergenekonyigitErbil Nas
authored
feat: add dark mode
Co-authored-by: Gökhan Akın <gokhan.akin@trendyol.com> Co-authored-by: Ergenekon Yigit <ergenekon.yigit@trendyol.com> Co-authored-by: Erbil Nas <erbil.nas@trendyol.com>
1 parent ee76948 commit e91ec88

File tree

14 files changed

+538
-41
lines changed

14 files changed

+538
-41
lines changed

.storybook/DocsContainer.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { DocsContainer as BaseContainer, DocsContainerProps } from '@storybook/blocks';
2+
import { create, themes } from '@storybook/theming';
3+
import * as React from 'react';
4+
5+
const customDarkTheme = create({
6+
...themes.dark,
7+
base: 'dark',
8+
appBg: '#030713',
9+
appContentBg: '#030713',
10+
barBg: '#030713',
11+
});
12+
13+
export const DocsContainer: React.FC<React.PropsWithChildren<DocsContainerProps>> = ({ children, context }) => {
14+
const currentTheme = context?.store?.globals?.globals?.theme || 'light';
15+
const [theme, setTheme] = React.useState(currentTheme);
16+
17+
React.useEffect(() => {
18+
setTheme(currentTheme);
19+
}, [currentTheme]);
20+
21+
return React.createElement(
22+
BaseContainer,
23+
{ theme: theme === 'dark' ? customDarkTheme : themes.light, context },
24+
children
25+
);
26+
};

.storybook/baklava-theme.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,50 @@
11
import { create } from '@storybook/theming';
22

3-
export default create({
3+
/**
4+
* Light Theme for Storybook UI
5+
* Colors based on Storybook's default light theme and Baklava brand colors
6+
*/
7+
export const lightTheme = create({
48
base: 'light',
9+
10+
// Brand
511
brandTitle: 'Baklava Design System',
612
brandUrl: 'https://github.com/Trendyol/baklava',
713
brandImage: 'https://user-images.githubusercontent.com/127687/230370329-71295041-f5fc-4e12-8bf5-f37e98831efb.svg',
14+
15+
// Colors
816
colorPrimary: '#F27A1A',
917
colorSecondary: '#273142',
18+
19+
// UI
20+
appBg: '#F6F9FC',
21+
appContentBg: '#F6F9FC',
22+
appPreviewBg: '#ffffff',
23+
appBorderColor: '#e6e6e6',
24+
appBorderRadius: 4,
25+
26+
// Typography
1027
fontBase: 'RubikVariable, sans-serif',
11-
fontCode:
12-
'"Operator Mono","Fira Code Retina","Fira Code","FiraCode-Retina","Andale Mono","Lucida Console",Consolas,Monaco,monospace',
28+
fontCode: '"Operator Mono","Fira Code Retina","Fira Code","FiraCode-Retina","Andale Mono","Lucida Console",Consolas,Monaco,monospace',
1329
textColor: '#273142',
30+
textInverseColor: '#ffffff',
31+
textMutedColor: '#666666',
32+
33+
// Toolbar
34+
barTextColor: '#273142',
35+
barSelectedColor: '#F27A1A',
36+
barBg: '#ffffff',
37+
barHoverColor: '#F27A1A',
38+
39+
// Form
40+
inputBg: '#ffffff',
41+
inputBorder: '#e6e6e6',
42+
inputTextColor: '#273142',
43+
inputBorderRadius: 4,
44+
45+
// Button
46+
buttonBg: '#F6F9FC',
47+
buttonBorder: '#D9E8F2',
1448
});
49+
50+
export default lightTheme;

.storybook/manager.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { addons } from '@storybook/addons';
2-
import baklavaTheme from './baklava-theme';
1+
import { addons } from "@storybook/manager-api";
2+
import { lightTheme } from "./baklava-theme";
33

4-
addons.setConfig({ theme: baklavaTheme });
4+
// Static light theme for Storybook UI
5+
// Dark mode only affects the iframe preview, not the sidebar/toolbar
6+
addons.setConfig({
7+
theme: lightTheme,
8+
sidebar: {
9+
showRoots: true,
10+
},
11+
});

.storybook/preview-head.html

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,82 @@
1-
<script src="https://cdn.dsmcdn.com/hedwig/latest/hedwig.js" data-appId="6514f2ad-479b-4d90-b3d5-f8362b34adfc" data-apiKey="5A35jcVHRxiP6ojnrXXjKIWTSLfiNyuj0zCt-K4yI3Ew4gyadnKz2ldxfDNnhN3MnNsM0g=="></script>
2-
<link rel="preload" href="./assets/rubik-latin-variable-wghtOnly-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
1+
<script
2+
src="https://cdn.dsmcdn.com/hedwig/latest/hedwig.js"
3+
data-appId="6514f2ad-479b-4d90-b3d5-f8362b34adfc"
4+
data-apiKey="5A35jcVHRxiP6ojnrXXjKIWTSLfiNyuj0zCt-K4yI3Ew4gyadnKz2ldxfDNnhN3MnNsM0g=="
5+
></script>
6+
<script>
7+
window.__getStorybookTheme = function () {
8+
var urlParams = new URLSearchParams(window.location.search);
9+
var globals = urlParams.get("globals");
10+
if (globals) {
11+
var themeMatch = globals.match(/theme:([^;]+)/);
12+
if (themeMatch) return themeMatch[1];
13+
}
14+
15+
try {
16+
if (window.parent && window.parent !== window) {
17+
var parentTheme = window.parent.document.documentElement.getAttribute("data-theme");
18+
if (parentTheme) return parentTheme;
19+
}
20+
} catch (e) {
21+
}
22+
23+
try {
24+
if (window.top && window.top !== window) {
25+
var previewIframe = window.top.document.getElementById("storybook-preview-iframe");
26+
if (previewIframe && previewIframe.contentDocument) {
27+
var iframeTheme =
28+
previewIframe.contentDocument.documentElement.getAttribute("data-theme");
29+
if (iframeTheme) return iframeTheme;
30+
}
31+
}
32+
} catch (e) {
33+
}
34+
35+
try {
36+
var stored = localStorage.getItem("storybook-globals");
37+
if (stored) {
38+
var parsed = JSON.parse(stored);
39+
return parsed.theme || "light";
40+
}
41+
} catch (e) {}
42+
43+
return "light";
44+
};
45+
46+
window.__applyStorybookTheme = function () {
47+
var theme = window.__getStorybookTheme();
48+
document.documentElement.setAttribute("data-theme", theme);
49+
return theme;
50+
};
51+
52+
window.__applyStorybookTheme();
53+
</script>
54+
<link
55+
rel="preload"
56+
href="./assets/rubik-latin-variable-wghtOnly-normal.woff2"
57+
as="font"
58+
type="font/woff2"
59+
crossorigin="anonymous"
60+
/>
361
<link rel="stylesheet" href="./themes/default.css" />
62+
<link rel="stylesheet" href="./themes/dark.css" />
463
<script type="module" src="./baklava.js"></script>
564
<style>
6-
.innerZoomElementWrapper > * {
7-
vertical-align: top;
8-
}
9-
table {
10-
width: 100%;
11-
}
12-
code {
13-
font-size: 12px;
14-
}
15-
16-
bl-dialog {
17-
font: var(--bl-font-body-text-2)
18-
}
19-
20-
.limited-width {
21-
max-width: 300px;
22-
}
65+
.innerZoomElementWrapper > * {
66+
vertical-align: top;
67+
}
68+
table {
69+
width: 100%;
70+
}
71+
code {
72+
font-size: 12px;
73+
}
74+
75+
bl-dialog {
76+
font: var(--bl-font-body-text-2);
77+
}
78+
79+
.limited-width {
80+
max-width: 300px;
81+
}
2382
</style>

.storybook/preview.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { setCustomElementsManifest } from '@storybook/web-components';
22
import customElements from '../dist/custom-elements.json';
3+
import '../src/themes/dark.css';
4+
import '../src/themes/default.css';
5+
import { DocsContainer } from './DocsContainer';
36

47
setCustomElementsManifest(customElements);
58

69
export const parameters = {
710
actions: { argTypesRegex: '^on[A-Z].*' },
811
viewMode: 'docs',
912
docs: {
13+
container: DocsContainer,
1014
transformSource: source =>
1115
source
1216
.replace(/<!--\?lit\$[0-9]+\$-->|<!--\??-->/g, '')
@@ -31,6 +35,19 @@ export const parameters = {
3135
};
3236

3337
export const globalTypes = {
38+
theme: {
39+
name: 'theme',
40+
description: 'Global theme for components',
41+
defaultValue: 'light',
42+
toolbar: {
43+
icon: 'circlehollow',
44+
items: [
45+
{ value: 'light', icon: 'sun', title: 'Light Mode' },
46+
{ value: 'dark', icon: 'moon', title: 'Dark Mode' },
47+
],
48+
dynamicTitle: true,
49+
},
50+
},
3451
version: {
3552
name: 'version',
3653
description: 'Select version Stable/Beta',
@@ -47,6 +64,26 @@ export const globalTypes = {
4764

4865

4966
export const decorators = [
67+
(storyFn, context) => {
68+
const theme = context.globals.theme || 'light';
69+
70+
document.documentElement.setAttribute('data-theme', theme);
71+
72+
const previewBody = document.body;
73+
previewBody.setAttribute('data-theme', theme);
74+
75+
previewBody.style.backgroundColor = 'var(--bl-color-neutral-full)';
76+
previewBody.style.color = 'var(--bl-color-neutral-darkest)';
77+
78+
try {
79+
if (window.parent && window.parent !== window) {
80+
window.parent.postMessage({ type: 'STORYBOOK_THEME_CHANGED', theme }, '*');
81+
}
82+
} catch (e) {
83+
}
84+
85+
return storyFn();
86+
},
5087
(storyFn, context) => {
5188
if (context.globals.version === 'stable' && window.parent.location.hostname.includes('next')) {
5289
window.parent.location.assign('https://baklava.design' + window.parent.location.search);
@@ -57,3 +94,4 @@ export const decorators = [
5794
return storyFn();
5895
}
5996
];
97+

docs/customizing-baklava-theme.stories.mdx

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ to provide a list of component that you can customize every part of it. Instead
99
uses it.
1010

1111
But there are still many customization options in Baklava, those doesn't effect UX result of the components a lot. These are design tokens and a set of
12-
design token definitions are named as a "theme". Baklava comes with a default theme that you can import from `themes/default.css` file and will provide
13-
more soon (like a dark theme). But you can also create your own theme or extend/override some part of the default theme in your applications.
12+
design token definitions are named as a "theme". Baklava comes with a default theme that you can import from `themes/default.css` file and also provides
13+
a dark theme from `themes/dark.css` file. You can also create your own theme or extend/override some part of the default theme in your applications.
1414

1515
## Creating your own theme
1616

@@ -36,6 +36,34 @@ If you want to change a small set of the design tokens, you may consider to exte
3636

3737
With this, you can -for example- only override color palette for your app and continue to use typography or spacing rules from the default theme.
3838

39+
## Using Dark Theme
40+
41+
Baklava provides a built-in dark theme that you can use in your application. To enable dark mode:
42+
43+
```html
44+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@trendyol/baklava/dist/themes/default.css" />
45+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@trendyol/baklava/dist/themes/dark.css" />
46+
47+
<html data-theme="dark">
48+
<!-- All components will use dark theme -->
49+
<bl-button>Click Me</bl-button>
50+
</html>
51+
```
52+
53+
Or you can toggle dark mode dynamically with JavaScript:
54+
55+
```html
56+
<script>
57+
function toggleDarkMode(isDark) {
58+
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
59+
}
60+
61+
// Listen to system preference
62+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
63+
toggleDarkMode(prefersDark);
64+
</script>
65+
```
66+
3967
## Using themes in a smaller scope
4068

4169
Our theme files are setting CSS variables on `:root` level. That means they are being set on document level. But since we are only talking about
@@ -70,6 +98,23 @@ This opportunity gives a big power for handling esceptional use cases like:
7098
* Using dark theme in a part of your document (like header or footer)
7199
* Having more color or spacing options inside your app.
72100

101+
For example, you can use dark theme only in header:
102+
103+
```html
104+
<link rel="stylesheet" href="path/to/themes/default.css" />
105+
<link rel="stylesheet" href="path/to/themes/dark.css" />
106+
107+
<header class="dark-theme">
108+
<!-- Dark mode components -->
109+
<bl-button>Menu</bl-button>
110+
</header>
111+
112+
<main>
113+
<!-- Light mode components -->
114+
<bl-button>Content</bl-button>
115+
</main>
116+
```
117+
73118
## Changing default styles of components
74119

75120
In addition to setting design tokens, some of our components has their own CSS custom properties to make customisation on their style. And if you want

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"@storybook/addon-mdx-gfm": "^7.4.3",
9292
"@storybook/addon-viewport": "^7.4.3",
9393
"@storybook/jest": "^0.2.2",
94+
"@storybook/manager-api": "7.4.3",
9495
"@storybook/testing-library": "^0.2.2",
9596
"@storybook/web-components": "7.4.3",
9697
"@storybook/web-components-vite": "^7.4.3",

0 commit comments

Comments
 (0)