Skip to content

Commit

Permalink
feat(DarkModeToggler): Migrate and add stories to theme toggler 🎉 (#5236
Browse files Browse the repository at this point in the history
)

Co-authored-by: Claudio Wunder <cwunder@gnome.org>
Co-authored-by: Claudio Wunder <cwunder@hubspot.com>
  • Loading branch information
3 people authored Apr 20, 2023
1 parent 79b5134 commit bb46dfe
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 5 deletions.
7 changes: 6 additions & 1 deletion .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Preview } from '@storybook/react';
import NextImage from 'next/image';
import { ThemeProvider } from 'next-themes';
import App from '../pages/_app.mdx';
import { pageProps } from './constants';

Expand All @@ -24,7 +25,11 @@ const preview: Preview = {
};

export const decorators = [
Story => <App Component={Story} pageProps={pageProps} />,
Story => (
<ThemeProvider>
<App Component={Story} pageProps={pageProps} />
</ThemeProvider>
),
];

Object.defineProperty(NextImage, 'default', {
Expand Down
1 change: 1 addition & 0 deletions .stylelintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build
public
storybook-static
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DarkModeToggle Component render dark mode toggle 1`] = `
<div>
<button
aria-pressed="false"
class="darkModeToggle"
type="button"
>
<span
class="sr-only"
>
components.header.buttons.toggleDarkMode
</span>
<svg
class="light-mode-only"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0V0z"
fill="none"
/>
<path
d="M14 2c1.82 0 3.53.5 5 1.35-2.99 1.73-5 4.95-5 8.65s2.01 6.92 5 8.65A9.973 9.973 0 0114 22C8.48 22 4 17.52 4 12S8.48 2 14 2z"
/>
</svg>
<svg
class="dark-mode-only"
fill="currentColor"
height="1em"
stroke="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0z"
fill="none"
/>
<path
d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58a.996.996 0 00-1.41 0 .996.996 0 000 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37a.996.996 0 00-1.41 0 .996.996 0 000 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 000-1.41l-1.06-1.06zm1.06-10.96a.996.996 0 000-1.41.996.996 0 00-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36a.996.996 0 000-1.41.996.996 0 00-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"
/>
</svg>
</button>
</div>
`;
53 changes: 53 additions & 0 deletions components/Common/DarkModeToggle/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import DarkModeToggle from '../index';
import { IntlProvider } from 'react-intl';

let mockCurrentTheme = '';

const mockToggleTheme = jest.fn().mockImplementation(() => {
mockCurrentTheme = mockCurrentTheme === 'dark' ? 'light' : 'dark';
});

// Mock dark mode module for controlling dark mode HOC behaviour
jest.mock('next-themes', () => ({
useTheme: () => {
return { theme: mockCurrentTheme, setTheme: mockToggleTheme };
},
}));

describe('DarkModeToggle Component', () => {
it('render dark mode toggle', () => {
const { container } = render(
<IntlProvider locale="en" onError={() => {}}>
<DarkModeToggle />
</IntlProvider>
);
expect(container).toMatchSnapshot();
});

it('switches dark theme to light theme', () => {
mockCurrentTheme = 'dark';
render(
<IntlProvider locale="en" onError={() => {}}>
<DarkModeToggle />
</IntlProvider>
);
const toggle = screen.getByRole('button');
userEvent.click(toggle);
expect(mockCurrentTheme).toBe('light');
});

it('switches light theme to dark theme', () => {
mockCurrentTheme = 'light';
render(
<IntlProvider locale="en" onError={() => {}}>
<DarkModeToggle />
</IntlProvider>
);
const toggle = screen.getByRole('button');
userEvent.click(toggle);
expect(mockCurrentTheme).toBe('dark');
});
});
8 changes: 8 additions & 0 deletions components/Common/DarkModeToggle/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.darkModeToggle {
background: none;
border: none;
color: var(--color-text-accent);
cursor: pointer;
line-height: 0;
padding: 0;
}
13 changes: 13 additions & 0 deletions components/Common/DarkModeToggle/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import DarkModeToggle from '.';
import type { Meta, StoryObj } from '@storybook/react';

const meta: Meta<typeof DarkModeToggle> = {
title: 'DarkModeToggle',
component: DarkModeToggle,
};

export default meta;

type Story = StoryObj<typeof DarkModeToggle>;

export const Default: Story = {};
37 changes: 37 additions & 0 deletions components/Common/DarkModeToggle/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { useTheme } from 'next-themes';
import { FormattedMessage } from 'react-intl';
import { MdLightMode, MdNightlight } from 'react-icons/md';
import styles from './index.module.scss';

const DarkModeToggle = () => {
const { theme, setTheme } = useTheme();

const isDark = theme === 'dark';

const toggleTheme = (isKeyPress?: boolean) => {
if (isKeyPress) {
return;
}

setTheme(isDark ? 'light' : 'dark');
};

return (
<button
type="button"
className={styles.darkModeToggle}
onClick={() => toggleTheme()}
onKeyPress={() => toggleTheme(true)}
aria-pressed={isDark}
>
<span className="sr-only">
<FormattedMessage id="components.header.buttons.toggleDarkMode" />
</span>
<MdNightlight className="light-mode-only" />
<MdLightMode className="dark-mode-only" />
</button>
);
};

export default DarkModeToggle;
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"isomorphic-dompurify": "^1.1.0",
"next": "13.2.0",
"next-sitemap": "^4.0.6",
"next-themes": "^0.2.1",
"nextra": "^2.2.20",
"node-version-data": "^1.1.0",
"npm-run-all": "^4.1.5",
Expand Down
12 changes: 12 additions & 0 deletions styles/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,15 @@ blockquote {
iframe {
border: none;
}

[data-theme='light'] .dark-mode-only,
[data-theme='dark'] .light-mode-only {
display: none;
}

.light-mode-only,
.dark-mode-only {
height: 18px;
padding: 9px;
width: 18px;
}
20 changes: 18 additions & 2 deletions styles/layout/_dark-theme.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
//TODO: Remove `body.dark`/.dark once DarkModeToggle from nodejs.dev has been integrated into nodejs.org

[data-theme='dark'] body,
body.dark {
background-color: $dark-black;
color: $white;
}

[data-theme='dark'] body,
.dark {
color-scheme: dark;

Expand All @@ -28,6 +32,7 @@ body.dark {

#main {
background-color: $dark-black;

p,
h1,
h2,
Expand All @@ -37,18 +42,21 @@ body.dark {

a {
color: $dark-green2;

&:hover {
color: $white;
}
}

.active > a {
.active>a {
background-color: $active-green;
color: $white;
}
}

header, .dark-theme-switcher img, .lang-picker-toggler img {
header,
.dark-theme-switcher img,
.lang-picker-toggler img {
background-color: $dark-black2;
}

Expand All @@ -71,6 +79,7 @@ body.dark {

a {
color: $dark-green2;

&:hover {
background-color: $dark-green2;
color: $white;
Expand All @@ -93,16 +102,20 @@ body.dark {

table {
background-color: $dark-black3;

th {
color: $white-alpha-b3;
}

td {
color: $white;
}

tr:only-child,
tr:nth-child(even) {
background-color: $dark-black2 !important;
}

tr:nth-child(odd) {
background-color: $black;
}
Expand All @@ -120,6 +133,7 @@ body.dark {
}

background-color: $dark-black2;

.openjsfoundation-footer {
background-color: $dark-black2;
}
Expand All @@ -133,6 +147,7 @@ body.dark {
a {
background-color: $dark-green;
color: #0aa007;

&:hover {
background-color: #438542;
}
Expand All @@ -153,6 +168,7 @@ body.dark {
font-size: 75%;
margin-left: 1em;
}

code {
background-color: $dark-code-background;
}
Expand Down
5 changes: 4 additions & 1 deletion styles/tokens.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//TODO: Remove .dark once DarkModeToggle from nodejs.dev has been integrated into nodejs.org

body {
--mono: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
--sans: 'Open Sans', sans-serif;
Expand Down Expand Up @@ -149,7 +151,8 @@ body {
--space-160: 16rem;
}

.dark {
.dark,
[data-theme='dark'] body {
/* Colors */
--color-brand-primary: var(--brand5);
--color-text-primary: var(--black4);
Expand Down

1 comment on commit bb46dfe

@vercel
Copy link

@vercel vercel bot commented on bb46dfe Apr 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.