@@ -81,7 +83,7 @@ const FilesExploreForm = ({ onBrowse: onBrowseProp }) => {
disabled={!isValid}
danger={!isValid}
title={t('app:actions.inspect')}
- style={{ borderRadius: '0 3px 3px 0' }}
+ style={{ borderRadius: '0 3px 3px 0', background: isDarkTheme ? 'var(--input-btn-bg)' : '' }}
onClick={onInspect}
bg='bg-teal'
className='ExploreFormButton button-reset pv1 ph2 ba f7 fw4 white overflow-hidden tc' >
@@ -92,7 +94,7 @@ const FilesExploreForm = ({ onBrowse: onBrowseProp }) => {
minWidth={0}
disabled={!isValid}
danger={!isValid}
- style={{ borderRadius: '0' }}
+ style={{ borderRadius: '0', background: isDarkTheme ? 'var(--input-btn-bg)' : '' }}
title={t('app:actions.browse')}
onClick={onBrowse}
className='ExploreFormButton button-reset pv1 ph2 ba f7 fw4 white bg-gray overflow-hidden tc' >
diff --git a/src/files/info-boxes/add-files-info/AddFilesInfo.js b/src/files/info-boxes/add-files-info/AddFilesInfo.js
index 4b021f7fb..ed438d02f 100644
--- a/src/files/info-boxes/add-files-info/AddFilesInfo.js
+++ b/src/files/info-boxes/add-files-info/AddFilesInfo.js
@@ -1,15 +1,19 @@
import React from 'react'
import { withTranslation, Trans } from 'react-i18next'
import Box from '../../../components/box/Box.js'
+import { useTheme } from '../../../hooks/theme'
-const AddFilesInfo = ({ t }) => (
-
-
-
- No files here yet! Add files to your local IPFS node by clicking the Import button above.
-
-
-
-)
+const AddFilesInfo = ({ t }) => {
+ const { isDarkTheme } = useTheme()
+ return (
+
+
+
+ No files here yet! Add files to your local IPFS node by clicking the Import button above.
+
+
+
+ )
+}
export default withTranslation('files')(AddFilesInfo)
diff --git a/src/hooks/theme.ts b/src/hooks/theme.ts
new file mode 100644
index 000000000..78d4b1155
--- /dev/null
+++ b/src/hooks/theme.ts
@@ -0,0 +1,10 @@
+import React from 'react'
+import { ThemeContext, ThemeContextValues } from '../context/theme-provider'
+
+export const useTheme = (): ThemeContextValues => {
+ const context = React.useContext(ThemeContext)
+ if (context == null) {
+ throw new Error('Theme context is missing You probably forgot to wrap the component depending on theme in
')
+ }
+ return context
+}
diff --git a/src/index.css b/src/index.css
index 87793d8c3..4497268d4 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,15 +1,87 @@
-@import './reset.css';
+@import "./reset.css";
@import "../node_modules/tachyons";
/* They forgot to include word break: https://github.com/tachyons-css/tachyons/issues/563 */
@import "../node_modules/tachyons/src/_word-break.css";
@import "../node_modules/ipfs-css";
+:root {
+ --input-bg-dark: #121212;
+ --input-btn-bg: #2b2e30;
+ --teal-dark: #2b79801a;
+ --box-dark: #1a1c1e;
+ --world-map-text-dark: #e8e6e3;
+ --charcoal-muted: #9d9488;
+ --filter-peers-dark: #121212;
+ --element-bg-light: #fbfbfb;
+ --dataset-name: #d3dce4;
+}
+
body {
overflow-y: scroll;
}
-.placeholder-light::placeholder{
- color: #CAD3D8;
+[data-theme="dark"] {
+ --background: #181a1b;
+ --text: #e8e6e3;
+ --element-bg: #1a1c1e;
+ --navy-dark: #0b3a53;
+ --navy-text-color: rgb(202, 198, 191);
+ --snow-muted: rgb(28, 30, 31);
+ --border-color: rgba(140, 130, 115, 0.5);
+
+ body {
+ transition: background 0.3s ease-in;
+ }
+
+ h2, .black, .montserrat {
+ color: var(--world-map-text-dark) !important;
+ }
+
+ /* from inspecting the DOM, most of the classes here are from tachyon and ipfs-css
+ * so when the data-theme attr is set to dark, we'll have them updated
+ */
+ .bg-snow-muted {
+ background: var(--snow-muted);
+ }
+
+ .charcoal {
+ color: rgb(196, 191, 183);
+ }
+
+ section {
+ background: var(--element-bg);
+ }
+
+ .navy {
+ color: var(--navy-text-color);
+ }
+
+ .joyride-app-explore < div {
+ border: 1px solid red;
+ }
+
+ .webui-header {
+ background: var(--snow-muted) !important;
+ }
+
+ .ReactVirtualized__Table__headerRow {
+ background: var(--box-dark);
+ border-bottom: 1px solid var(--border-color);
+ }
+
+ .ReactVirtualized__Table__row {
+ border-bottom: 1px solid var(--border-color);
+ }
+}
+
+html #root {
+ background-color: var(--background);
+ color: var(--text);
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.placeholder-light::placeholder {
+ color: #cad3d8;
}
.bg-near-white {
@@ -26,7 +98,7 @@ html, body, #root {
@media only screen and (min-width: 60em) {
.appOverlay {
- width: calc(100% - 148px)
+ width: calc(100% - 148px);
}
}
diff --git a/src/peers/PeersPage.js b/src/peers/PeersPage.js
index 4f2bcc266..ecef13079 100644
--- a/src/peers/PeersPage.js
+++ b/src/peers/PeersPage.js
@@ -14,34 +14,37 @@ import PeersTable from './PeersTable/PeersTable.js'
import AddConnection from './AddConnection/AddConnection.js'
import CliTutorMode from '../components/cli-tutor-mode/CliTutorMode.js'
import { cliCmdKeys, cliCommandList } from '../bundles/files/consts.js'
+import { useTheme } from '../hooks/theme'
-const PeersPage = ({ t, toursEnabled, handleJoyrideCallback }) => (
-
-
- {t('title')} | IPFS
-
+const PeersPage = ({ t, toursEnabled, handleJoyrideCallback }) => {
+ const { isDarkTheme } = useTheme()
+ return (
+
+
+ {t('title')} | IPFS
+
-
-
-
-
-
-
-
-
-
-)
+ )
+}
export default connect(
'selectToursEnabled',
diff --git a/src/peers/PeersTable/PeersTable.js b/src/peers/PeersTable/PeersTable.js
index 93de11880..a2c54fd10 100644
--- a/src/peers/PeersTable/PeersTable.js
+++ b/src/peers/PeersTable/PeersTable.js
@@ -10,6 +10,7 @@ import Cid from '../../components/cid/Cid.js'
import { sortByProperty } from '../../lib/sort.js'
import './PeersTable.css'
+import { useTheme } from '../../hooks/theme'
const flagRenderer = (flagCode, isPrivate) => {
// Check if the OS is Windows to render the flags as SVGs
@@ -102,6 +103,7 @@ const rowClassRenderer = ({ index }, peers = [], selectedPeers) => {
}
const FilterInput = ({ setFilter, t, filteredCount }) => {
+ const { isDarkTheme } = useTheme()
return (
{
type='text'
placeholder='Filter peers'
onChange={(e) => setFilter(e.target.value)}
+ style={{ background: isDarkTheme ? 'var(--filter-peers-dark)' : '', border: isDarkTheme ? '0.4px solid var(--border-color)' : '' }}
/>
{/* Now to display the total number of peers filtered out on the right side of the inside of the input */}
{filteredCount}
@@ -122,6 +125,7 @@ export const PeersTable = ({ className, t, peerLocationsForSwarm, selectedPeers
const [sortBy, setSortBy] = useState('latency')
const [sortDirection, setSortDirection] = useState(SortDirection.ASC)
const [filter, setFilter] = useState('')
+ const { isDarkTheme } = useTheme()
const sort = useCallback(({ sortBy, sortDirection }) => {
setSortBy(sortBy)
@@ -168,7 +172,7 @@ export const PeersTable = ({ className, t, peerLocationsForSwarm, selectedPeers
)
return (
-
+
{ awaitedPeerLocationsForSwarm &&
{({ width }) => (
@@ -185,6 +189,7 @@ export const PeersTable = ({ className, t, peerLocationsForSwarm, selectedPeers
rowGetter={({ index }) => sortedList[index]}
sort={sort}
sortBy={sortBy}
+ background={isDarkTheme ? 'var(--box-dark)' : '' }
sortDirection={sortDirection}>
diff --git a/src/peers/WorldMap/WorldMap.js b/src/peers/WorldMap/WorldMap.js
index b4b8b2c92..969c8dbf1 100644
--- a/src/peers/WorldMap/WorldMap.js
+++ b/src/peers/WorldMap/WorldMap.js
@@ -14,6 +14,7 @@ import Popover from '../../components/popover/Popover.js'
// Styles
import './WorldMap.css'
import Cid from '../../components/cid/Cid.js'
+import { useTheme } from '../../hooks/theme'
const calculateWidth = (windowWidth) => {
// the d3 generated svg width includes a lot of ocean, that we crop for now, as it looks weird.
@@ -49,6 +50,7 @@ const WorldMap = ({ t, className, selectedPeers, doSetSelectedPeers }) => {
const [width, setWidth] = useState(calculateWidth(window.innerWidth))
const [height, setHeight] = useState(calculateHeight(width))
const [selectedTimeout, setSelectedTimeout] = useState(null)
+ const { isDarkTheme } = useTheme()
useEffect(() => {
const debouncedHandleResize = debounce(() => {
@@ -100,8 +102,8 @@ const WorldMap = ({ t, className, selectedPeers, doSetSelectedPeers }) => {
-
-
{t('app:terms.peers')}
+
+
{t('app:terms.peers')}
diff --git a/src/reset.css b/src/reset.css
index 90f447a1c..bd6864097 100644
--- a/src/reset.css
+++ b/src/reset.css
@@ -10,7 +10,7 @@ button {
button:not(.disabled) {
cursor: pointer;
}
-
+
button:not(.default):focus-visible {
outline: 1px solid #bbb;
outline-offset: -1px;
@@ -32,3 +32,12 @@ button.hoverable-button:hover {
button.hoverable-button:focus {
outline: none;
}
+
+/* override tachyons */
+[data-theme='dark'] .bg-white {
+ background-color: var(--background) !important;
+}
+
+[data-theme='dark'] .near-black {
+ color: var(--text) !important;
+}
diff --git a/tsconfig.json b/tsconfig.json
index ec69689fc..42e62a1b4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -57,6 +57,8 @@
"include": [
"**/*.ts",
"@types",
+ "src/context",
+ "src/hooks",
// "src/**/*.js", // TODO: Include all js files when typecheck passes
"src/bundles/files/**/*.js",
"src/bundles/analytics.js",