diff --git a/website/src/components/Header.jsx b/website/src/components/Header.jsx
index e56e287..1c6d303 100644
--- a/website/src/components/Header.jsx
+++ b/website/src/components/Header.jsx
@@ -2,14 +2,18 @@ import LogoIcon from './../images/icons/github.svg';
import React from 'react';
import { Stack } from 'layout-ui';
import TwitterIcon from './../images/icons/twitter.svg';
+import ThemeIcon from './../images/icons/theme.svg';
import { styled } from '@filbert-js/core';
+import { colors } from './../themes/utils';
const Link = styled.a`
display: inline-flex;
align-items: center;
+ color: ${colors(`app.color`)};
`;
-export function Header() {
+export function Header(props) {
+
return (
+
+
+
);
}
diff --git a/website/src/components/Layout.jsx b/website/src/components/Layout.jsx
index 30929ba..166d725 100644
--- a/website/src/components/Layout.jsx
+++ b/website/src/components/Layout.jsx
@@ -7,7 +7,7 @@ import React from 'react';
import { Sidebar } from './Sidebar';
import { ThemeProvider } from '@filbert-js/theming';
import { colors } from './../themes/utils';
-import { tokens as lightTheme } from '../themes/light';
+import { useTheme } from '../themes/hook';
const Screen = styled.div`
display: grid;
@@ -18,7 +18,9 @@ const Screen = styled.div`
padding: 1rem 2rem;
width: 100%;
max-width: 64em;
- color: ${colors(`text.body`)};
+
+ background: ${colors(`app.background-color`)};
+ color: ${colors(`app.color`)};
@media screen and (max-width: 52em) {
grid-template-columns: 1fr;
}
@@ -62,33 +64,33 @@ const ToggleButton = styled.button`
border: 0;
}
`;
-const globalStyles = `
- @import url('https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap');
+export function Layout({ children }) {
+ const [theme, toggleTheme] = useTheme();
+ const [toggle, setToggle] = React.useState(true);
+
+ const globalStyles = `
+ @import url('https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap');
body {
font-family: 'Inter', sans-serif;
margin: 0;
- }
-
+ background: ${colors(`app.background-color`)({ theme })};
+ color: ${colors(`app.color`)({ theme })};
+ }
* {
box-sizing: border-box;
}
`;
-export function Layout({ children }) {
- const [toggle, setToggle] = React.useState(true);
-
return (
-
+
-
+
-
-
{children}
setToggle(!toggle)}>
diff --git a/website/src/components/markdown-overrides.js b/website/src/components/markdown-overrides.js
index dd23ccb..6ba1e84 100644
--- a/website/src/components/markdown-overrides.js
+++ b/website/src/components/markdown-overrides.js
@@ -16,11 +16,12 @@ export const Paragraph = styled.p`
`;
export const Pre = styled.pre`
padding: 10px 20px;
- background-color: #f6f8fa;
+ background: ${colors(`app.background-color`)};
border-radius: 6px;
+ color: ${colors(`text.body`)};
`;
export const Blockquote = styled.div`
- background: #f9f9f9;
+ background: ${colors(`app.background-color`)};
border-left: 10px solid #ccc;
margin: 1.5em 0;
padding: 1em 10px 1em 10px;
diff --git a/website/src/images/icons/theme.svg b/website/src/images/icons/theme.svg
new file mode 100644
index 0000000..4731abc
--- /dev/null
+++ b/website/src/images/icons/theme.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/website/src/themes/dark.js b/website/src/themes/dark.js
new file mode 100644
index 0000000..5d345e9
--- /dev/null
+++ b/website/src/themes/dark.js
@@ -0,0 +1,176 @@
+/*
+ Tokens:
+ Define your scales first
+
+ Source: react-ui
+*/
+
+export const tokens = {
+ name: 'React UI Light',
+ space: {
+ 0: 0,
+ 1: '4px',
+ 2: '8px',
+ 3: '12px',
+ 4: '16px',
+ 5: '20px',
+ 6: '24px',
+ 7: '28px',
+ 8: '32px',
+ 9: '36px',
+ 10: '40px',
+ 11: '44px',
+ 12: '48px',
+ 13: '52px',
+ 14: '56px',
+ 15: '60px',
+ 16: '64px',
+ },
+ radii: [0, '2px', '4px', '16px', '50%'],
+ fontSizes: {
+ 0: 0,
+ 1: '10px',
+ 2: '12px',
+ 3: '14px',
+ 4: '16px',
+ 5: '20px',
+ 6: '24px',
+ 7: '32px',
+ 8: '48px',
+ 9: '64px',
+ 10: '72px',
+ },
+ fontWeights: {
+ thin: 100,
+ light: 300,
+ normal: 400,
+ medium: 500,
+ semibold: 600,
+ bold: 700,
+ extrabold: 800,
+ black: 900,
+ },
+ lineHeights: {
+ compact: '1.2',
+ default: '1.6',
+ cosy: '2',
+ },
+ breakpoints: {
+ 0: '576px',
+ 1: '768px',
+ 2: '992px',
+ },
+
+ durations: {
+ 0: 0,
+ 1: '75ms',
+ 2: '100ms',
+ 3: '150ms',
+ 4: '200ms',
+ 5: '300ms',
+ 6: '500ms',
+ 7: '1000ms',
+ 8: '2500ms',
+ },
+
+ // based on elevation levels
+ shadows: {
+ 0: 'none',
+ 1: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
+ 2: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
+ 3: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
+ 4: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ },
+
+ colors: {
+ white: '#fff',
+ reds: {
+ 100: '#F8E4E4',
+ 200: '#EFA6A6',
+ 300: '#E06161',
+ 400: '#D95252',
+ 500: '#D12D2D',
+ 600: '#B41F1F',
+ 700: '#A20808',
+ 800: '#821919',
+ 900: '#5E1717',
+ },
+ yellows: {
+ 100: '#FDF3D7',
+ 200: '#FAECC2',
+ 300: '#F8E8BA',
+ 400: '#FAE29F',
+ 500: '#FFD97E',
+ 600: '#F4CA64',
+ 700: '#CAA53D',
+ 800: '#8C6D1F',
+ 900: '#5C4813',
+ },
+ blues: {
+ 100: '#EFF8FF',
+ 200: '#B7DBF7',
+ 300: '#A8D1F2',
+ 400: '#63A2D8',
+ 500: '#036FCA',
+ 600: '#217CC9',
+ 700: '#2368A2',
+ 800: '#1A4971',
+ 900: '#203D54',
+ },
+ greens: {
+ 100: '#E3FCEC',
+ 200: '#A8EEC1',
+ 300: '#8FF2B2',
+ 400: '#4BE38C',
+ 500: '#22D66F',
+ 600: '#38C172',
+ 700: '#259D58',
+ 800: '#197741',
+ 900: '#145239',
+ },
+ grays: {
+ 100: '#f5faff',
+ 200: '#E1E7EC',
+ 300: '#D1D9E0',
+ 400: '#C8D0D7',
+ 500: '#AEBECD',
+ 600: '#929FB1',
+ 700: '#6E7A8A',
+ 800: '#404B5A',
+ 900: '#202833',
+ },
+ },
+};
+
+// recommended: use the same space grid for size
+tokens.sizes = { ...tokens.space };
+
+/*
+ Decisions:
+ You can create aliases in scales based on the scale.
+ */
+
+tokens.colors.text = {
+ subtle: 'grays.200',
+ body: 'white',
+ link: 'grays.400',
+ 'link-hover': 'white',
+};
+
+tokens.colors.error = {
+ background: 'reds.100',
+ border: 'reds.300',
+ text: 'reds.700',
+};
+
+tokens.colors.app = {
+ 'background-color': 'grays.900',
+ color: 'white',
+ 'border-color': 'grays.200',
+};
+
+tokens.fontSizes.Heading = {
+ page: 8, // reads from tokens.fontSizes.8
+ section: 6,
+ paragraph: 4,
+};
diff --git a/website/src/themes/hook.js b/website/src/themes/hook.js
new file mode 100644
index 0000000..d7a0c7d
--- /dev/null
+++ b/website/src/themes/hook.js
@@ -0,0 +1,42 @@
+import { useCallback, useEffect, useState } from 'react';
+
+import { tokens as darkTheme } from './dark';
+import { tokens as lightTheme } from './light';
+
+const themes = { light: lightTheme, dark: darkTheme };
+function getThemeName() {
+ if(typeof window==='object'){
+ const localTheme = window.localStorage.getItem('theme');
+ return window.matchMedia &&
+ window.matchMedia('(prefers-color-scheme: dark)').matches &&
+ !localTheme
+ ? 'dark'
+ : localTheme
+ ? localTheme
+ : 'light';
+ }else{
+ return 'light';
+ }
+}
+export const useTheme = () => {
+ const [theme, setTheme] = useState(getThemeName());
+
+ const setMode = useCallback((mode) => {
+ window.localStorage.setItem('theme', mode);
+ setTheme(mode);
+ }, []);
+
+ const toggleTheme = () => {
+ if (theme === 'light') {
+ setMode('dark');
+ } else {
+ setMode('light');
+ }
+ };
+
+ useEffect(() => {
+ setMode(getThemeName());
+ }, [setMode]);
+
+ return [themes[theme], toggleTheme];
+};