documentation-site/pages/_app.jsx (225 lines of code) (raw):
/*
Copyright (c) Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
/* eslint-env browser */
//
import * as React from "react";
import {
createThemedStyled,
createThemedUseStyletron,
createThemedWithStyle,
BaseProvider,
DarkTheme,
DarkThemeMove,
LightTheme,
LightThemeMove,
} from "baseui";
import App from "next/app";
import Head from "next/head";
import { Provider as StyletronProvider } from "styletron-react";
import { Block } from "baseui/block";
import Router from "next/router";
import { styletron } from "../helpers/styletron";
import { trackPageView } from "../helpers/ga";
import DirectionContext from "../components/direction-context";
const breakpoints = {
small: 670,
medium: 920,
large: 1280,
};
const ResponsiveTheme = Object.keys(breakpoints).reduce(
(acc, key) => {
acc.mediaQuery[key] =
`@media screen and (min-width: ${breakpoints[key]}px)`;
return acc;
},
{
breakpoints,
mediaQuery: {},
}
);
const themes = {
LightTheme: { ...LightTheme, ...ResponsiveTheme },
LightThemeMove: { ...LightThemeMove, ...ResponsiveTheme },
DarkTheme: { ...DarkTheme, ...ResponsiveTheme },
DarkThemeMove: { ...DarkThemeMove, ...ResponsiveTheme },
};
export const themedStyled = createThemedStyled();
export const themedWithStyle = createThemedWithStyle();
export const themedUseStyletron =
createThemedUseStyletron();
const DARK_MEDIA_QUERY = "(prefers-color-scheme: dark)";
const LIGHT_MEDIA_QUERY = "(prefers-color-scheme: light)";
const blockProps = {
color: "contentPrimary",
backgroundColor: "backgroundPrimary",
maxWidth: "100vw",
minHeight: "100vh",
overflow: "hidden",
};
export default class MyApp extends App {
constructor(props) {
super(props);
this.state = {
theme: themes.LightTheme,
direction: "ltr",
themeSet: false,
};
this.mediaQueryListener =
this.mediaQueryListener.bind(this);
}
componentDidMount() {
Router.onRouteChangeComplete = (url) => {
trackPageView(url.split("?")[0]);
};
if (window.matchMedia) {
const mmDark = window.matchMedia(DARK_MEDIA_QUERY);
const mmLight = window.matchMedia(LIGHT_MEDIA_QUERY);
// if no theme is set in localStorage, set theme based on user's OS preference
if (
!this.getThemeStyle() &&
mmDark.media === DARK_MEDIA_QUERY
) {
const theme = mmDark.matches ? "dark" : "light";
localStorage.setItem("docs-theme", theme);
}
mmDark.addListener(this.mediaQueryListener);
mmLight.addListener(this.mediaQueryListener);
}
this.setTheme();
}
componentWillUnmount() {
if (window.matchMedia) {
const mmDark = window.matchMedia(DARK_MEDIA_QUERY);
const mmLight = window.matchMedia(LIGHT_MEDIA_QUERY);
mmDark.removeListener(this.mediaQueryListener);
mmLight.removeListener(this.mediaQueryListener);
}
}
mediaQueryListener(e) {
if (e && e.matches) {
if (e.media === DARK_MEDIA_QUERY) {
this.setThemeStyle("dark");
} else if (e.media === LIGHT_MEDIA_QUERY) {
this.setThemeStyle("light");
}
this.setTheme();
}
}
setTheme() {
const search = window.location.search;
const ls = window.localStorage;
const config = {
font: "system",
theme: "light",
};
const presetFont = ls.getItem("docs-font");
const presetTheme = ls.getItem("docs-theme");
let fontToSet;
let themeToSet;
if (search.includes("font=move")) {
fontToSet = "move";
ls.setItem("docs-font", fontToSet);
}
if (search.includes("font=system")) {
fontToSet = "system";
ls.setItem("docs-font", fontToSet);
}
if (search.includes("theme=dark")) {
themeToSet = "dark";
ls.setItem("docs-theme", themeToSet);
}
if (search.includes("theme=light")) {
themeToSet = "light";
ls.setItem("docs-theme", themeToSet);
}
config.font = fontToSet || presetFont || config.font;
config.theme =
themeToSet || presetTheme || config.theme;
const themeName =
config.theme === "dark"
? config.font === "move"
? "DarkThemeMove"
: "DarkTheme"
: config.font === "move"
? "LightThemeMove"
: "LightTheme";
this.setState({
themeSet: true,
theme: themes[themeName],
});
}
getThemeStyle() {
return localStorage.getItem("docs-theme");
}
setThemeStyle(theme) {
localStorage.setItem("docs-theme", theme);
}
toggleTheme() {
const theme = this.getThemeStyle();
if (theme === "dark") {
this.setThemeStyle("light");
} else {
this.setThemeStyle("dark");
}
this.setTheme();
}
toggleDirection() {
if (this.state.direction === "rtl") {
this.setState({
themeSet: true,
direction: "ltr",
theme: { ...this.state.theme, direction: "ltr" },
});
if (document.body) {
document.body.dir = "ltr";
}
} else {
this.setState({
themeSet: true,
direction: "rtl",
theme: { ...this.state.theme, direction: "rtl" },
});
if (document.body) {
document.body.dir = "rtl";
}
}
}
render() {
const { Component, pageProps, path } = this.props;
return (
<React.Fragment>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
</Head>
<StyletronProvider value={styletron}>
<BaseProvider theme={this.state.theme}>
<Block {...blockProps}>
<DirectionContext.Provider
value={this.state.direction}
>
{this.state.themeSet && (
<Component
{...pageProps}
path={path}
toggleTheme={this.toggleTheme.bind(
this
)}
toggleDirection={this.toggleDirection.bind(
this
)}
/>
)}
</DirectionContext.Provider>
</Block>
</BaseProvider>
</StyletronProvider>
</React.Fragment>
);
}
}