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";