diff --git a/public/favicon.ico b/public/favicon.ico index 6cd7212..f5f1d12 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/components/footer/index.js b/src/components/footer/index.js index 25bae25..07d9987 100644 --- a/src/components/footer/index.js +++ b/src/components/footer/index.js @@ -1,14 +1,12 @@ import React, { Component } from 'react' import { Link } from 'react-router-dom' -import Settings from '../settings' class Footer extends Component { render() { return window === window.top ? ( ) : null diff --git a/src/components/header/index.js b/src/components/header/index.js index bb01716..e5fb897 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -1,5 +1,7 @@ import React, { Component } from 'react' + import Search from '../search' +import Settings from '../settings' import { Link } from 'react-router-dom' class Header extends Component { @@ -46,6 +48,7 @@ class Header extends Component { Home + ) : null } diff --git a/src/components/modal/index.js b/src/components/modal/index.js new file mode 100644 index 0000000..2f9b105 --- /dev/null +++ b/src/components/modal/index.js @@ -0,0 +1,54 @@ +import React, { Component } from "react"; +import { createPortal } from "react-dom"; +import withClickOutside from "react-click-outside"; + +class Modal extends Component { + constructor() { + super(); + this.el = null; + } + + componentDidMount() { + this.el = document.createElement("div"); + document.querySelector(".settings-wrapper").appendChild(this.el); + } + + componentWillUnmount() { + if (this.el) { + this.el.remove(); + } + } + + handleClickOutside(event) { + const { closeOnOutsideClick, handleClose } = this.props; + + if (closeOnOutsideClick) { + event.preventDefault(); + return handleClose(); + } + } + + render() { + const { children, handleClose, isOpen, title } = this.props; + + if (!isOpen) return null; + + return createPortal( +
+ {title &&

{title}

} + {children} + +
, + this.el + ); + } +} + +Modal.defaultProps = { + closeOnOutsideClick: true, + isOpen: false +}; + +export default withClickOutside(Modal); diff --git a/src/components/settings/index.js b/src/components/settings/index.js index df3cb1b..2297236 100644 --- a/src/components/settings/index.js +++ b/src/components/settings/index.js @@ -1,66 +1,71 @@ -import React, { Component } from 'react' -import { compose } from 'redux' -import { connect } from 'react-redux' -import { updateSetting } from '../../store/settings' -import withClickOutside from 'react-click-outside' +import React, { Component, Fragment } from "react"; +import { connect } from "react-redux"; +import { updateSetting } from "../../store/settings"; -import Toggle from '../toggle' +import Modal from "../modal"; +import Toggle from "../toggle"; class Settings extends Component { constructor() { - super() + super(); this.state = { open: false - } + }; } handleClickOutside(event) { if (this.state.open) { - event.preventDefault() - this.setState({ open: false }) + event.preventDefault(); + this.setState({ open: false }); } } render() { - const { settings } = this.props - const { open } = this.state + const { settings } = this.props; + const { open } = this.state; return ( -
+ - {open && ( -
- -

Settings

+ this.setState({ open: false })} + > + +

+ Light text on dark background (defaults to OS preference) +

- -

- Reduce eye strain for low-light reading. -

-
- )} -
- ) + +

+ Reduce eye strain for low-light reading. +

+ + + ); } } -const mapStateToProps = ({ settings }) => ({ settings }) -const mapDispatchToProps = { updateSetting } +const mapStateToProps = ({ settings }) => ({ settings }); +const mapDispatchToProps = { updateSetting }; -export default compose( - connect(mapStateToProps, mapDispatchToProps), - withClickOutside -)(Settings) +export default connect( + mapStateToProps, + mapDispatchToProps +)(Settings); diff --git a/src/images/settings.svg b/src/images/settings.svg new file mode 100644 index 0000000..10d6078 --- /dev/null +++ b/src/images/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/index.js b/src/index.js index ce53501..5df4859 100644 --- a/src/index.js +++ b/src/index.js @@ -1,19 +1,20 @@ -import React from 'react' -import { BrowserRouter } from 'react-router-dom' -import { Provider } from 'react-redux' -import ReactDOM from 'react-dom' -import configureStore from './store' -import initReactFastclick from 'react-fastclick' -import registerServiceWorker from './registerServiceWorker' -import './styles/styles.css' +import React from "react"; +import { BrowserRouter } from "react-router-dom"; +import { Provider } from "react-redux"; +import ReactDOM from "react-dom"; +import configureStore from "./store"; +import initReactFastclick from "react-fastclick"; +import registerServiceWorker from "./registerServiceWorker"; +import "./styles/styles.css"; +import "./lib/favicon"; -import App from './routes' +import App from "./routes"; -if ('ontouchstart' in document.documentElement) { - document.body.style.cursor = 'pointer' +if ("ontouchstart" in document.documentElement) { + document.body.style.cursor = "pointer"; } -initReactFastclick() +initReactFastclick(); ReactDOM.render( @@ -21,6 +22,6 @@ ReactDOM.render( , - document.getElementById('root') -) -registerServiceWorker() + document.getElementById("root") +); +registerServiceWorker(); diff --git a/src/lib/favicon/index.js b/src/lib/favicon/index.js new file mode 100644 index 0000000..4b49478 --- /dev/null +++ b/src/lib/favicon/index.js @@ -0,0 +1,28 @@ +function applyIcon(type) { + const link = document.querySelector("link[rel*='icon']"); + + if (type === "dark") { + link.href = + "data:image/png;base64,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"; + } else { + link.href = + "data:image/png;base64,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"; + } +} + +var dmQuery = window.matchMedia("(prefers-color-scheme: dark)"); +var lmQuery = window.matchMedia("(prefers-color-scheme: light)"); + +// Check on initial load if dark mode is already there. Apply the dark +// mode favicon if true. +if (dmQuery.matches) { + applyIcon("dark"); +} + +lmQuery.addListener(function() { + if (lmQuery.matches) { + applyIcon("light"); + } else if (dmQuery.matches) { + applyIcon("dark"); + } +}); diff --git a/src/routes/app/index.js b/src/routes/app/index.js index b53d0ea..c764429 100644 --- a/src/routes/app/index.js +++ b/src/routes/app/index.js @@ -1,19 +1,40 @@ -import React from 'react' -import { connect } from 'react-redux' +import React, { Component } from "react"; +import { connect } from "react-redux"; -import Header from '../../components/header' -import Footer from '../../components/footer' +import Header from "../../components/header"; +import Footer from "../../components/footer"; -const App = ({ classNames, children }) => ( -
-
- {children} -
-
-) +class App extends Component { + componentDidMount() { + if (this.props.darkMode) { + document.documentElement.style.backgroundColor = "black"; + } + } + + componentDidUpdate({ darkMode }) { + if (this.props.darkMode !== darkMode) { + document.documentElement.style.backgroundColor = this.props.darkMode + ? "black" + : "transparent"; + } + } + + render() { + const { children, classNames } = this.props; + + return ( +
+
+ {children} +
+ ); + } +} const mapStateToProps = ({ settings }) => ({ + darkMode: settings.darkMode, classNames: Object.keys(settings).filter(setting => settings[setting]) -}) +}); -export default connect(mapStateToProps)(App) +export default connect(mapStateToProps)(App); diff --git a/src/store/settings/index.js b/src/store/settings/index.js index 9d0ade7..a393564 100644 --- a/src/store/settings/index.js +++ b/src/store/settings/index.js @@ -3,26 +3,29 @@ export const updateSetting = (name, value) => dispatch => .then(() => localStorage.setItem(name, value)) .then(() => dispatch({ - type: 'SETTINGS/UPDATE', + type: "SETTINGS/UPDATE", payload: { name, value } }) - ) + ); -const getBooleanValue = key => localStorage.getItem(key) === 'true' +const getBooleanValue = key => localStorage.getItem(key) === "true"; const initialState = { - lowContrast: getBooleanValue('lowContrast') -} + darkMode: localStorage.getItem("darkMode") + ? getBooleanValue("darkMode") + : window.matchMedia("(prefers-color-scheme: dark)").matches, + lowContrast: getBooleanValue("lowContrast") +}; export default (state = initialState, action) => { switch (action.type) { - case 'SETTINGS/UPDATE': - const { name, value } = action.payload + case "SETTINGS/UPDATE": + const { name, value } = action.payload; return { ...state, [name]: value - } + }; default: - return state + return state; } -} +}; diff --git a/src/styles/_layout.scss b/src/styles/_layout.scss index 0d94df4..ee5b96c 100644 --- a/src/styles/_layout.scss +++ b/src/styles/_layout.scss @@ -16,15 +16,15 @@ height: $header-height; text-indent: -9999px; overflow: hidden; - color: currentColor; + color: currentColor !important; margin: auto; &:visited { - color: currentColor; + color: currentColor !important; } &:before { - content: 'W'; + content: "W"; position: absolute; top: 50%; left: 50%; @@ -40,7 +40,7 @@ top: 0; height: $header-height; background-color: rgba(white, 0.975); - border-bottom: thin solid rgba(black, 0.1); + border-bottom: thin solid rgba(gray, 0.25); transition: all 350ms ease; display: flex; justify-content: space-between; @@ -48,7 +48,7 @@ padding-right: $header-height - 0.5rem; &.scrolled { - box-shadow: 0 0 1rem rgba(black, 0.1); + box-shadow: 0 0 1rem rgba(gray, 0.1); border-color: transparent; } @@ -57,13 +57,13 @@ transform: translateY(-100%); } - div { + > div { flex: 1; } .logo { &:after { - content: ''; + content: ""; position: absolute; top: $header-height / 4; right: 0; @@ -82,6 +82,7 @@ width: 100%; border: 0; background: transparent; + color: currentColor; appearance: none; height: $header-height; line-height: $header-height / 2; @@ -100,19 +101,18 @@ left: 0; right: 0; background-color: white; - border-top: thin solid rgba(black, 0.1); + border-top: thin solid rgba(gray, 0.25); max-height: calc(100vh - #{$header-height}); overflow: auto; z-index: 2; - box-shadow: 0 100vh 0 100vh rgba(black, 0.5), - 0 0.5rem 0.5rem rgba(black, 0.125); + box-shadow: 0 100vh 0 100vh rgba(gray, 0.5), 0 0.5rem 0.5rem rgba(gray, 0.125); } .search-result { display: block; padding: 1rem; line-height: 1; - border-top: thin solid rgba(black, 0.1); + border-top: thin solid rgba(gray, 0.25); color: inherit; text-decoration: none; @@ -126,7 +126,7 @@ &:hover, &.active { - background-color: rgba(black, 0.075); + background-color: rgba(gray, 0.075); } } @@ -185,7 +185,7 @@ $bar-height: 0.166rem; &:before, &:after { - content: ''; + content: ""; position: absolute; top: 50%; left: 50%; @@ -227,7 +227,7 @@ $bar-height: 0.166rem; max-width: calc(100vw - 1.5rem); max-height: calc(95vh - #{$header-height}); overflow: auto; - box-shadow: 0 0.25rem 2rem rgba(black, 0.125); + box-shadow: 0 0.25rem 2rem rgba(gray, 0.125); border-radius: 0.25rem; a { @@ -236,7 +236,7 @@ $bar-height: 0.166rem; font-size: 0.8rem; color: currentColor; text-decoration: none; - border-top: thin solid rgba(black, 0.1); + border-top: thin solid rgba(gray, 0.1); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -252,7 +252,7 @@ $bar-height: 0.166rem; &:hover, &:active { - background-color: rgba(black, 0.075); + background-color: rgba(gray, 0.075); } .section-level { @@ -290,18 +290,23 @@ $bar-height: 0.166rem; padding: 1.5rem 2rem; background: white; border-radius: 0.25rem; - box-shadow: 0 0 0 100vh rgba(black, 0.75); + box-shadow: 0 0 0 100vh rgba(gray, 0.75); z-index: 1000; max-width: calc(100vw - 2rem); max-height: calc(100vh - 2rem); overflow: auto; text-align: left; + + h3 { + margin-top: 0; + margin-bottom: 2rem; + } } .close { position: absolute; - top: -0.25rem; - right: -0.25rem; + top: 0; + right: 0; width: $header-height; height: $header-height; text-indent: -9999px; @@ -315,7 +320,7 @@ $bar-height: 0.166rem; &:before, &:after { - content: ''; + content: ""; position: absolute; top: 50%; left: 50%; @@ -336,18 +341,20 @@ $bar-height: 0.166rem; } .settings-button { - padding: 0.5rem 1rem; - border: thin solid rgba(black, 0.25); - border-radius: 0.25rem; - margin-bottom: 0.5rem; -} - -.settings { - h3 { - margin-top: 0; - border-bottom: thin solid rgba(black, 0.25); - padding-bottom: 0.75rem; - } + position: relative; + width: $header-height; + height: $header-height; + padding: 0; + border: 0; + border-right: thin solid rgba(gray, 0.25); + margin-right: 0.5rem; + text-indent: -9999px; + text-align: left; + outline: 0; + opacity: 0.75; + cursor: pointer; + background: url(../images/settings.svg) no-repeat center; + background-size: 1.25rem; } .settings-hint { @@ -401,12 +408,12 @@ $bar-height: 0.166rem; } .toggle-ui { - background: rgba(black, 0.25); + background: rgba(gray, 0.25); transition: all 200ms ease; pointer-events: none; &:before { - content: ''; + content: ""; position: absolute; top: 50%; left: 0; diff --git a/src/styles/_page.scss b/src/styles/_page.scss index 8950e77..f3917ac 100644 --- a/src/styles/_page.scss +++ b/src/styles/_page.scss @@ -1,4 +1,4 @@ -@import 'thumbs'; +@import "thumbs"; $sidebar-width: 20rem; @@ -7,10 +7,19 @@ $sidebar-width: 20rem; p:first-of-type { b { - font-family: 'Playfair Display', 'PT Serif', 'Lora', Georgia, serif; + font-family: "Playfair Display", "PT Serif", "Lora", Georgia, serif; } } + .mediaContainer { + margin: 1rem auto; + } + + #coordinates { + display: block; + text-align: center; + } + h2 { margin: 0; counter-increment: section; @@ -22,14 +31,14 @@ $sidebar-width: 20rem; margin: 2em 0; &:before { - content: counter(section) '.'; + content: counter(section) "."; display: block; font-size: 75%; font-weight: normal; } &:after { - content: ''; + content: ""; position: absolute; bottom: 0; left: 50%; @@ -120,6 +129,8 @@ div.hatnote { table { border: 0 !important; + background-color: transparent !important; + color: inherit !important; &.infobox { font-size: 90%; @@ -136,7 +147,7 @@ table { background-color: transparent !important; } - th[colspan='2'], + th[colspan="2"], .adr, .fn { font-weight: bold; @@ -144,11 +155,11 @@ table { padding: 1rem; } - td[colspan='2'] { + td[colspan="2"] { text-align: center; } - th[scope='row'] { + th[scope="row"] { text-align: right; padding-right: 1.5rem; } @@ -222,7 +233,7 @@ table.mbox-small { font-style: italic; } -.root > div[style='width:70%'] { +.root > div[style="width:70%"] { width: auto; } @@ -315,7 +326,7 @@ pre { font-size: 75%; &:after { - content: '. '; + content: ". "; } } } diff --git a/src/styles/_settings.scss b/src/styles/_settings.scss index 6c2ce10..835dff0 100644 --- a/src/styles/_settings.scss +++ b/src/styles/_settings.scss @@ -1,7 +1,58 @@ .lowContrast { - opacity: 0.75; + &, + .header { + background: hsl(2000, 10%, 75%); + color: #444; + } img { opacity: 0.75; } } + +.darkMode { + &, + .header { + background: black; + color: white; + } + + &.lowContrast { + color: #aaa; + } + + .toggle-ui:before, + .search-results { + background: black; + } + + .loading:after { + background: linear-gradient(rgba(black, 0), black), + linear-gradient(90deg, rgba(black, 0), rgba(black, 0.5)); + } + + .settings-button { + filter: invert(0.9); + } + + .modal { + background: black; + box-shadow: 0 0 0 100vh rgba(0, 0, 0, 0.75); + } + + a { + color: hsl(40, 90%, 40%); + -webkit-tap-highlight-color: hsla(40, 90%, 40%, 0.25); + + &:visited { + color: hsl(30, 90%, 40%); + } + + &:focus, + &:hover, + &:active { + color: hsl(40, 90%, 30%); + outline: 0; + } + } +} diff --git a/src/styles/_typography.scss b/src/styles/_typography.scss index 3100d68..027b3ba 100644 --- a/src/styles/_typography.scss +++ b/src/styles/_typography.scss @@ -1,12 +1,11 @@ :root { - color: $color-dark; font-family: $serif-stack; font-size: 110%; line-height: 1.666; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-text-size-adjust: none; - -webkit-tap-highlight-color: rgba(black, 0); + -webkit-tap-highlight-color: rgba(gray, 0); @media (min-width: 36rem) { font-size: 120%; diff --git a/src/styles/styles.css b/src/styles/styles.css index 80c9793..92fbdef 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -1,12 +1,11 @@ :root { - color: #222; font-family: "PT Serif", "Lora", Georgia, serif; font-size: 110%; line-height: 1.666; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-text-size-adjust: none; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } + -webkit-tap-highlight-color: rgba(128, 128, 128, 0); } @media (min-width: 36rem) { :root { font-size: 120%; } } @@ -92,12 +91,12 @@ table { height: 3.25rem; text-indent: -9999px; overflow: hidden; - color: currentColor; + color: currentColor !important; margin: auto; } .logo:visited { - color: currentColor; } + color: currentColor !important; } .logo:before { - content: 'W'; + content: "W"; position: absolute; top: 50%; left: 50%; @@ -111,22 +110,22 @@ table { top: 0; height: 3.25rem; background-color: rgba(255, 255, 255, 0.975); - border-bottom: thin solid rgba(0, 0, 0, 0.1); + border-bottom: thin solid rgba(128, 128, 128, 0.25); transition: all 350ms ease; display: flex; justify-content: space-between; z-index: 5; padding-right: 2.75rem; } .header.scrolled { - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + box-shadow: 0 0 1rem rgba(128, 128, 128, 0.1); border-color: transparent; } .header.hidden { box-shadow: none; transform: translateY(-100%); } - .header div { + .header > div { flex: 1; } .header .logo:after { - content: ''; + content: ""; position: absolute; top: 0.8125rem; right: 0; @@ -141,6 +140,7 @@ table { width: 100%; border: 0; background: transparent; + color: currentColor; appearance: none; height: 3.25rem; line-height: 1.625rem; @@ -155,17 +155,17 @@ table { left: 0; right: 0; background-color: white; - border-top: thin solid rgba(0, 0, 0, 0.1); + border-top: thin solid rgba(128, 128, 128, 0.25); max-height: calc(100vh - 3.25rem); overflow: auto; z-index: 2; - box-shadow: 0 100vh 0 100vh rgba(0, 0, 0, 0.5), 0 0.5rem 0.5rem rgba(0, 0, 0, 0.125); } + box-shadow: 0 100vh 0 100vh rgba(128, 128, 128, 0.5), 0 0.5rem 0.5rem rgba(128, 128, 128, 0.125); } .search-result { display: block; padding: 1rem; line-height: 1; - border-top: thin solid rgba(0, 0, 0, 0.1); + border-top: thin solid rgba(128, 128, 128, 0.25); color: inherit; text-decoration: none; } .search-result:first-child { @@ -173,7 +173,7 @@ table { .search-result:visited { color: currentColor; } .search-result:hover, .search-result.active { - background-color: rgba(0, 0, 0, 0.075); } + background-color: rgba(128, 128, 128, 0.075); } .search-result-title, .search-result-description { @@ -219,7 +219,7 @@ table { cursor: pointer; color: currentColor; } .page-sections-button:before, .page-sections-button:after { - content: ''; + content: ""; position: absolute; top: 50%; left: 50%; @@ -249,7 +249,7 @@ table { max-width: calc(100vw - 1.5rem); max-height: calc(95vh - 3.25rem); overflow: auto; - box-shadow: 0 0.25rem 2rem rgba(0, 0, 0, 0.125); + box-shadow: 0 0.25rem 2rem rgba(128, 128, 128, 0.125); border-radius: 0.25rem; } .page-sections-nav a { display: block; @@ -257,7 +257,7 @@ table { font-size: 0.8rem; color: currentColor; text-decoration: none; - border-top: thin solid rgba(0, 0, 0, 0.1); + border-top: thin solid rgba(128, 128, 128, 0.1); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -267,7 +267,7 @@ table { .page-sections-nav a:visited { color: currentColor; } .page-sections-nav a:hover, .page-sections-nav a:active { - background-color: rgba(0, 0, 0, 0.075); } + background-color: rgba(128, 128, 128, 0.075); } .page-sections-nav a .section-level { opacity: 0.5; font-size: 80%; } @@ -293,17 +293,20 @@ table { padding: 1.5rem 2rem; background: white; border-radius: 0.25rem; - box-shadow: 0 0 0 100vh rgba(0, 0, 0, 0.75); + box-shadow: 0 0 0 100vh rgba(128, 128, 128, 0.75); z-index: 1000; max-width: calc(100vw - 2rem); max-height: calc(100vh - 2rem); overflow: auto; text-align: left; } + .modal h3 { + margin-top: 0; + margin-bottom: 2rem; } .close { position: absolute; - top: -0.25rem; - right: -0.25rem; + top: 0; + right: 0; width: 3.25rem; height: 3.25rem; text-indent: -9999px; @@ -315,7 +318,7 @@ table { color: currentColor; transform: scale(0.75); } .close:before, .close:after { - content: ''; + content: ""; position: absolute; top: 50%; left: 50%; @@ -330,15 +333,20 @@ table { transform: translate(-50%, -50%) rotate(45deg); } .settings-button { - padding: 0.5rem 1rem; - border: thin solid rgba(0, 0, 0, 0.25); - border-radius: 0.25rem; - margin-bottom: 0.5rem; } - -.settings h3 { - margin-top: 0; - border-bottom: thin solid rgba(0, 0, 0, 0.25); - padding-bottom: 0.75rem; } + position: relative; + width: 3.25rem; + height: 3.25rem; + padding: 0; + border: 0; + border-right: thin solid rgba(128, 128, 128, 0.25); + margin-right: 0.5rem; + text-indent: -9999px; + text-align: left; + outline: 0; + opacity: 0.75; + cursor: pointer; + background: url(../images/settings.svg) no-repeat center; + background-size: 1.25rem; } .settings-hint { opacity: 0.75; @@ -382,11 +390,11 @@ table { transform: translateX(1.25rem) translateY(-50%); } .toggle-ui { - background: rgba(0, 0, 0, 0.25); + background: rgba(128, 128, 128, 0.25); transition: all 200ms ease; pointer-events: none; } .toggle-ui:before { - content: ''; + content: ""; position: absolute; top: 50%; left: 0; @@ -524,7 +532,12 @@ table { .root { counter-reset: section; } .root p:first-of-type b { - font-family: 'Playfair Display', 'PT Serif', 'Lora', Georgia, serif; } + font-family: "Playfair Display", "PT Serif", "Lora", Georgia, serif; } + .root .mediaContainer { + margin: 1rem auto; } + .root #coordinates { + display: block; + text-align: center; } .root h2 { margin: 0; counter-increment: section; } @@ -539,7 +552,7 @@ table { font-size: 75%; font-weight: normal; } .root h2 .mw-headline:after { - content: ''; + content: ""; position: absolute; bottom: 0; left: 50%; @@ -610,7 +623,9 @@ div.hatnote { text-align: center; } table { - border: 0 !important; } + border: 0 !important; + background-color: transparent !important; + color: inherit !important; } table.infobox { font-size: 90%; border: 0; } @@ -619,15 +634,15 @@ table { table.infobox th, table.infobox td { background-color: transparent !important; } - table.infobox th[colspan='2'], + table.infobox th[colspan="2"], table.infobox .adr, table.infobox .fn { font-weight: bold; text-align: center; padding: 1rem; } - table.infobox td[colspan='2'] { + table.infobox td[colspan="2"] { text-align: center; } - table.infobox th[scope='row'] { + table.infobox th[scope="row"] { text-align: right; padding-right: 1.5rem; } table.infobox th, @@ -676,7 +691,7 @@ table.mbox-small { border: 0; font-style: italic; } -.root > div[style='width:70%'] { +.root > div[style="width:70%"] { width: auto; } .mw-editsection, @@ -742,7 +757,7 @@ pre { #toc .tocnumber { font-size: 75%; } #toc .tocnumber:after { - content: '. '; } + content: ". "; } .root table h2 { background-color: transparent; @@ -830,7 +845,41 @@ pre { to { transform: translate(-50%, -50%) rotate(360deg); } } -.lowContrast { +.lowContrast, +.lowContrast .header { + background: #b9c1c6; + color: #444; } + +.lowContrast img { opacity: 0.75; } - .lowContrast img { - opacity: 0.75; } + +.darkMode, +.darkMode .header { + background: black; + color: white; } + +.darkMode.lowContrast { + color: #aaa; } + +.darkMode .toggle-ui:before, +.darkMode .search-results { + background: black; } + +.darkMode .loading:after { + background: linear-gradient(rgba(0, 0, 0, 0), black), linear-gradient(90deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5)); } + +.darkMode .settings-button { + filter: invert(0.9); } + +.darkMode .modal { + background: black; + box-shadow: 0 0 0 100vh rgba(0, 0, 0, 0.75); } + +.darkMode a { + color: #c2850a; + -webkit-tap-highlight-color: rgba(194, 133, 10, 0.25); } + .darkMode a:visited { + color: #c2660a; } + .darkMode a:focus, .darkMode a:hover, .darkMode a:active { + color: #916308; + outline: 0; } diff --git a/src/styles/styles.scss b/src/styles/styles.scss index 4541b94..315f3b4 100644 --- a/src/styles/styles.scss +++ b/src/styles/styles.scss @@ -1,13 +1,12 @@ -$serif-stack: 'PT Serif', 'Lora', Georgia, serif; -$sans-stack: 'Roboto', 'HelveticaNeue-Light', 'Helvetica Neue Light', - 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; -$title-stack: 'Playfair Display', $serif-stack; -$color-dark: #222; +$serif-stack: "PT Serif", "Lora", Georgia, serif; +$sans-stack: "Roboto", "HelveticaNeue-Light", "Helvetica Neue Light", + "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; +$title-stack: "Playfair Display", $serif-stack; $header-height: 3.25rem; -@import 'typography'; -@import 'layout'; -@import 'home'; -@import 'page'; -@import 'loading'; -@import 'settings'; +@import "typography"; +@import "layout"; +@import "home"; +@import "page"; +@import "loading"; +@import "settings";