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> ); } }