dark mode with css variables instead
This commit is contained in:
parent
c6e6ddfa65
commit
a3544fb67f
1
.babelrc
1
.babelrc
@ -3,7 +3,6 @@
|
|||||||
"next/babel"
|
"next/babel"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"styled-components",
|
|
||||||
[
|
[
|
||||||
"inline-react-svg",
|
"inline-react-svg",
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,6 @@ import { useMe } from './me'
|
|||||||
import CommentEdit from './comment-edit'
|
import CommentEdit from './comment-edit'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import { NOFOLLOW_LIMIT } from '../lib/constants'
|
import { NOFOLLOW_LIMIT } from '../lib/constants'
|
||||||
import styled from 'styled-components'
|
|
||||||
|
|
||||||
function Parent ({ item, rootText }) {
|
function Parent ({ item, rootText }) {
|
||||||
const ParentFrag = () => (
|
const ParentFrag = () => (
|
||||||
@ -40,10 +39,6 @@ function Parent ({ item, rootText }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledComment = styled.div`
|
|
||||||
background-color: ${({ theme, includeParent }) => includeParent ? undefined : theme.commentBg};
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function Comment ({
|
export default function Comment ({
|
||||||
item, children, replyOpen, includeParent,
|
item, children, replyOpen, includeParent,
|
||||||
rootText, noComments, noReply
|
rootText, noComments, noReply
|
||||||
@ -69,8 +64,7 @@ export default function Comment ({
|
|||||||
const op = item.root.user.name === item.user.name
|
const op = item.root.user.name === item.user.name
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledComment
|
<div
|
||||||
includeParent={includeParent}
|
|
||||||
ref={ref} className={includeParent ? '' : `${styles.comment} ${collapse ? styles.collapsed : ''}`}
|
ref={ref} className={includeParent ? '' : `${styles.comment} ${collapse ? styles.collapsed : ''}`}
|
||||||
>
|
>
|
||||||
<div className={`${itemStyles.item} ${styles.item}`}>
|
<div className={`${itemStyles.item} ${styles.item}`}>
|
||||||
@ -162,7 +156,7 @@ export default function Comment ({
|
|||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</StyledComment>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
border-radius: .4rem;
|
border-radius: .4rem;
|
||||||
padding-top: .5rem;
|
padding-top: .5rem;
|
||||||
padding-left: .2rem;
|
padding-left: .2rem;
|
||||||
|
background-color: var(--theme-commentBg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment:not(:last-child) {
|
.comment:not(:last-child) {
|
||||||
|
@ -8,9 +8,9 @@ import Github from '../svgs/github-fill.svg'
|
|||||||
import Twitter from '../svgs/twitter-fill.svg'
|
import Twitter from '../svgs/twitter-fill.svg'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import useDarkMode from 'use-dark-mode'
|
import useDarkMode from 'use-dark-mode'
|
||||||
import styled from 'styled-components'
|
|
||||||
import Sun from '../svgs/sun-fill.svg'
|
import Sun from '../svgs/sun-fill.svg'
|
||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '../svgs/moon-fill.svg'
|
||||||
|
import { handleThemeChange } from '../public/darkmode'
|
||||||
|
|
||||||
const ChatPopover = (
|
const ChatPopover = (
|
||||||
<Popover>
|
<Popover>
|
||||||
@ -32,16 +32,6 @@ const ChatPopover = (
|
|||||||
</Popover>
|
</Popover>
|
||||||
)
|
)
|
||||||
|
|
||||||
const ContrastLink = styled.a`
|
|
||||||
color: ${({ theme }) => theme.color};
|
|
||||||
&:hover {
|
|
||||||
color: ${({ theme }) => theme.color};
|
|
||||||
}
|
|
||||||
& svg {
|
|
||||||
fill: ${({ theme }) => theme.color};
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function Footer ({ noLinks }) {
|
export default function Footer ({ noLinks }) {
|
||||||
const query = gql`
|
const query = gql`
|
||||||
{
|
{
|
||||||
@ -53,7 +43,7 @@ export default function Footer ({ noLinks }) {
|
|||||||
|
|
||||||
const darkMode = useDarkMode(false, {
|
const darkMode = useDarkMode(false, {
|
||||||
// set this so it doesn't try to use classes
|
// set this so it doesn't try to use classes
|
||||||
onChange: () => { }
|
onChange: handleThemeChange
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -108,9 +98,9 @@ export default function Footer ({ noLinks }) {
|
|||||||
/>
|
/>
|
||||||
</div>}
|
</div>}
|
||||||
<small>
|
<small>
|
||||||
<ContrastLink className='d-inline-block' href='https://github.com/stackernews/stacker.news'>
|
<a className={`d-inline-block ${styles.contrastLink}`} href='https://github.com/stackernews/stacker.news'>
|
||||||
This is free open source software<Github width={20} height={20} className='mx-1' />
|
This is free open source software<Github width={20} height={20} className='mx-1' />
|
||||||
</ContrastLink>
|
</a>
|
||||||
<span className='d-inline-block text-muted'>
|
<span className='d-inline-block text-muted'>
|
||||||
made with sound love in Austin<Texas className='mx-1' width={20} height={20} />
|
made with sound love in Austin<Texas className='mx-1' width={20} height={20} />
|
||||||
by<a href='https://twitter.com/k00bideh' className='text-twitter d-inline-block'><Twitter width={20} height={20} className='ml-1' />@k00bideh</a>
|
by<a href='https://twitter.com/k00bideh' className='text-twitter d-inline-block'><Twitter width={20} height={20} className='ml-1' />@k00bideh</a>
|
||||||
|
@ -9,3 +9,13 @@
|
|||||||
.connect:hover {
|
.connect:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contrastLink {
|
||||||
|
color: var(--theme-color);
|
||||||
|
}
|
||||||
|
.contrastLink:hover {
|
||||||
|
color: var(--theme-color);
|
||||||
|
}
|
||||||
|
.contrastLink svg {
|
||||||
|
fill: var(--theme-color);
|
||||||
|
}
|
@ -11,48 +11,6 @@ import { signOut, signIn, useSession } from 'next-auth/client'
|
|||||||
import { useLightning } from './lightning'
|
import { useLightning } from './lightning'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '../lib/rand'
|
||||||
import styled from 'styled-components'
|
|
||||||
|
|
||||||
const Brand = styled(Navbar.Brand)`
|
|
||||||
color: ${({ theme }) => theme.brandColor}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const StyledNavbar = styled(Navbar).attrs(({ theme }) => ({
|
|
||||||
variant: theme.navbarVariant,
|
|
||||||
className: styles.navbar
|
|
||||||
}))`
|
|
||||||
& .dropdown-menu {
|
|
||||||
background-color: ${({ theme }) => theme.body};
|
|
||||||
border: 1px solid ${({ theme }) => theme.borderColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
& .dropdown-item {
|
|
||||||
color: ${({ theme }) => theme.dropdownItemColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
& .dropdown-item:hover {
|
|
||||||
color: ${({ theme }) => theme.dropdownItemColorHover};
|
|
||||||
}
|
|
||||||
|
|
||||||
& .dropdown-item.active {
|
|
||||||
color: ${({ theme }) => theme.brandColor};
|
|
||||||
text-shadow: 0 0 10px var(--primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
& .dropdown-divider {
|
|
||||||
border-top: 1px solid ${({ theme }) => theme.borderColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
& .theme {
|
|
||||||
margin-right: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
fill: ${({ theme }) => theme.dropdownItemColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
& .theme:hover {
|
|
||||||
fill: ${({ theme }) => theme.dropdownItemColorHover};
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
function WalletSummary ({ me }) {
|
function WalletSummary ({ me }) {
|
||||||
return `${me?.sats} \\ ${me?.stacked}`
|
return `${me?.sats} \\ ${me?.stacked}`
|
||||||
@ -172,16 +130,16 @@ export default function Header () {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container className='px-sm-0'>
|
<Container className='px-sm-0'>
|
||||||
<StyledNavbar>
|
<Navbar>
|
||||||
<Nav
|
<Nav
|
||||||
className={styles.navbarNav}
|
className={styles.navbarNav}
|
||||||
activeKey={path}
|
activeKey={path}
|
||||||
>
|
>
|
||||||
<Link href='/' passHref>
|
<Link href='/' passHref>
|
||||||
<Brand className={`${styles.brand} d-none d-sm-block`}>STACKER NEWS</Brand>
|
<Navbar.Brand className={`${styles.brand} d-none d-sm-block`}>STACKER NEWS</Navbar.Brand>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href='/' passHref>
|
<Link href='/' passHref>
|
||||||
<Brand className={`${styles.brand} d-block d-sm-none`}>SN</Brand>
|
<Navbar.Brand className={`${styles.brand} d-block d-sm-none`}>SN</Navbar.Brand>
|
||||||
</Link>
|
</Link>
|
||||||
<Nav.Item className='d-md-flex d-none nav-dropdown-toggle'>
|
<Nav.Item className='d-md-flex d-none nav-dropdown-toggle'>
|
||||||
<SplitButton
|
<SplitButton
|
||||||
@ -217,7 +175,7 @@ export default function Header () {
|
|||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Corner />
|
<Corner />
|
||||||
</Nav>
|
</Nav>
|
||||||
</StyledNavbar>
|
</Navbar>
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@ -227,6 +185,7 @@ export function HeaderPreview () {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container className='px-sm-0'>
|
<Container className='px-sm-0'>
|
||||||
|
{/* still need to set variant */}
|
||||||
<Navbar className={styles.navbar}>
|
<Navbar className={styles.navbar}>
|
||||||
<Nav className='w-100 justify-content-between flex-wrap align-items-center'>
|
<Nav className='w-100 justify-content-between flex-wrap align-items-center'>
|
||||||
<Link href='/' passHref>
|
<Link href='/' passHref>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
margin-bottom: -.3rem;
|
margin-bottom: -.3rem;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
text-shadow: 0 0 10px #FADA5E;
|
text-shadow: 0 0 10px #FADA5E;
|
||||||
|
color: var(--theme-brandColor) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navLink {
|
.navLink {
|
||||||
|
105
pages/_app.js
105
pages/_app.js
@ -7,92 +7,10 @@ import PlausibleProvider from 'next-plausible'
|
|||||||
import { LightningProvider } from '../components/lightning'
|
import { LightningProvider } from '../components/lightning'
|
||||||
import { ItemActModal, ItemActProvider } from '../components/item-act'
|
import { ItemActModal, ItemActProvider } from '../components/item-act'
|
||||||
import getApolloClient from '../lib/apollo'
|
import getApolloClient from '../lib/apollo'
|
||||||
import { createGlobalStyle, ThemeProvider } from 'styled-components'
|
|
||||||
import useDarkMode from 'use-dark-mode'
|
|
||||||
|
|
||||||
const GlobalStyle = createGlobalStyle`
|
|
||||||
body {
|
|
||||||
background: ${({ theme }) => theme.body};
|
|
||||||
color: ${({ theme }) => theme.color};
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
|
||||||
color: inherit;
|
|
||||||
background-color: ${({ theme }) => theme.inputBg};
|
|
||||||
border-color: ${({ theme }) => theme.borderColor};
|
|
||||||
border-bottom-color: ${({ theme }) => theme.inputBg};
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control {
|
|
||||||
background-color: ${({ theme }) => theme.inputBg};
|
|
||||||
color: ${({ theme }) => theme.color};
|
|
||||||
border-color: ${({ theme }) => theme.borderColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:focus {
|
|
||||||
background-color: ${({ theme }) => theme.inputBg};
|
|
||||||
color: ${({ theme }) => theme.color};
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:disabled, .form-control[readonly] {
|
|
||||||
background-color: ${({ theme }) => theme.inputBg};
|
|
||||||
border-color: ${({ theme }) => theme.borderColor};
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clickToContext {
|
|
||||||
border-radius: .4rem;
|
|
||||||
padding: .2rem 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clickToContext:hover {
|
|
||||||
background-color: ${({ theme }) => theme.clickToContextColor};
|
|
||||||
}
|
|
||||||
|
|
||||||
.fresh {
|
|
||||||
background-color: ${({ theme }) => theme.clickToContextColor};
|
|
||||||
border-radius: .4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: ${({ theme }) => theme.body};
|
|
||||||
border-color: ${({ theme }) => theme.borderColor};
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const lightTheme = {
|
|
||||||
body: '#f5f5f5',
|
|
||||||
color: '#212529',
|
|
||||||
navbarVariant: 'light',
|
|
||||||
borderColor: '#ced4da',
|
|
||||||
inputBg: '#ffffff',
|
|
||||||
dropdownItemColor: 'inherit',
|
|
||||||
dropdownItemColorHover: 'rgba(0, 0, 0, 0.9)',
|
|
||||||
commentBg: 'rgba(0, 0, 0, 0.03)',
|
|
||||||
clickToContextColor: 'rgba(0, 0, 0, 0.05)',
|
|
||||||
brandColor: 'rgba(0, 0, 0, 0.9)'
|
|
||||||
}
|
|
||||||
|
|
||||||
const darkTheme = {
|
|
||||||
body: '#000000',
|
|
||||||
inputBg: '#000000',
|
|
||||||
navbarVariant: 'dark',
|
|
||||||
borderColor: 'rgb(255 255 255 / 50%)',
|
|
||||||
dropdownItemColor: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
dropdownItemColorHover: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
commentBg: 'rgba(255, 255, 255, 0.04)',
|
|
||||||
clickToContextColor: 'rgba(255, 255, 255, 0.08)',
|
|
||||||
color: '#f8f9fa',
|
|
||||||
brandColor: 'var(--primary) !important'
|
|
||||||
}
|
|
||||||
|
|
||||||
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
||||||
const client = getApolloClient()
|
const client = getApolloClient()
|
||||||
const darkMode = useDarkMode(false, {
|
|
||||||
// set this so it doesn't try to use clas
|
|
||||||
onChange: (e) => { console.log(e) }
|
|
||||||
})
|
|
||||||
/*
|
/*
|
||||||
If we are on the client, we populate the apollo cache with the
|
If we are on the client, we populate the apollo cache with the
|
||||||
ssr data
|
ssr data
|
||||||
@ -113,18 +31,15 @@ function MyApp ({ Component, pageProps: { session, ...props } }) {
|
|||||||
<Provider session={session}>
|
<Provider session={session}>
|
||||||
<ApolloProvider client={client}>
|
<ApolloProvider client={client}>
|
||||||
<MeProvider>
|
<MeProvider>
|
||||||
<ThemeProvider theme={darkMode.value ? darkTheme : lightTheme}>
|
<LightningProvider>
|
||||||
<GlobalStyle />
|
<FundErrorProvider>
|
||||||
<LightningProvider>
|
<FundErrorModal />
|
||||||
<FundErrorProvider>
|
<ItemActProvider>
|
||||||
<FundErrorModal />
|
<ItemActModal />
|
||||||
<ItemActProvider>
|
<Component {...props} />
|
||||||
<ItemActModal />
|
</ItemActProvider>
|
||||||
<Component {...props} />
|
</FundErrorProvider>
|
||||||
</ItemActProvider>
|
</LightningProvider>
|
||||||
</FundErrorProvider>
|
|
||||||
</LightningProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
</MeProvider>
|
</MeProvider>
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
@ -1,30 +1,18 @@
|
|||||||
import Document from 'next/document'
|
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||||
import { ServerStyleSheet } from 'styled-components'
|
|
||||||
|
|
||||||
export default class MyDocument extends Document {
|
class MyDocument extends Document {
|
||||||
static async getInitialProps (ctx) {
|
render () {
|
||||||
const sheet = new ServerStyleSheet()
|
return (
|
||||||
const originalRenderPage = ctx.renderPage
|
<Html>
|
||||||
|
<Head />
|
||||||
try {
|
<body>
|
||||||
ctx.renderPage = () =>
|
<script src='darkmode.js' />
|
||||||
originalRenderPage({
|
<Main />
|
||||||
enhanceApp: (App) => (props) =>
|
<NextScript />
|
||||||
sheet.collectStyles(<App {...props} />)
|
</body>
|
||||||
})
|
</Html>
|
||||||
|
)
|
||||||
const initialProps = await Document.getInitialProps(ctx)
|
|
||||||
return {
|
|
||||||
...initialProps,
|
|
||||||
styles: (
|
|
||||||
<>
|
|
||||||
{initialProps.styles}
|
|
||||||
{sheet.getStyleElement()}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
sheet.seal()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default MyDocument
|
||||||
|
@ -3,10 +3,9 @@ import Items from '../../components/items'
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { getGetServerSideProps } from '../../api/ssrApollo'
|
import { getGetServerSideProps } from '../../api/ssrApollo'
|
||||||
import { MORE_ITEMS } from '../../fragments/items'
|
import { MORE_ITEMS } from '../../fragments/items'
|
||||||
import { Nav } from 'react-bootstrap'
|
import { Nav, Navbar } from 'react-bootstrap'
|
||||||
import styles from '../../components/header.module.css'
|
import styles from '../../components/header.module.css'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { StyledNavbar } from '../../components/header'
|
|
||||||
|
|
||||||
export const getServerSideProps = getGetServerSideProps(MORE_ITEMS, { sort: 'top'})
|
export const getServerSideProps = getGetServerSideProps(MORE_ITEMS, { sort: 'top'})
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ export default function Index ({ data: { moreItems: { items, cursor } } }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<StyledNavbar>
|
<Navbar>
|
||||||
<Nav
|
<Nav
|
||||||
className={styles.navbarNav}
|
className={styles.navbarNav}
|
||||||
activeKey={path}
|
activeKey={path}
|
||||||
@ -67,7 +66,7 @@ export default function Index ({ data: { moreItems: { items, cursor } } }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
</Nav>
|
</Nav>
|
||||||
</StyledNavbar>
|
</Navbar>
|
||||||
<Items
|
<Items
|
||||||
items={items} cursor={cursor}
|
items={items} cursor={cursor}
|
||||||
variables={{ sort: 'top', within: router.query?.within }} rank
|
variables={{ sort: 'top', within: router.query?.within }} rank
|
||||||
|
71
public/darkmode.js
Normal file
71
public/darkmode.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Insert this script in your index.html right after the <body> tag.
|
||||||
|
// This will help to prevent a flash if dark mode is the default.
|
||||||
|
export const COLORS = {
|
||||||
|
light: {
|
||||||
|
body: '#f5f5f5',
|
||||||
|
color: '#212529',
|
||||||
|
navbarVariant: 'light',
|
||||||
|
navLink: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
navLinkFocus: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
navLinkActive: 'rgba(0, 0, 0, 0.9)',
|
||||||
|
borderColor: '#ced4da',
|
||||||
|
inputBg: '#ffffff',
|
||||||
|
dropdownItemColor: 'inherit',
|
||||||
|
dropdownItemColorHover: 'rgba(0, 0, 0, 0.9)',
|
||||||
|
commentBg: 'rgba(0, 0, 0, 0.03)',
|
||||||
|
clickToContextColor: 'rgba(0, 0, 0, 0.05)',
|
||||||
|
brandColor: 'rgba(0, 0, 0, 0.9)'
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
body: '#000000',
|
||||||
|
inputBg: '#000000',
|
||||||
|
navLink: 'rgba(255, 255, 255, 0.5)',
|
||||||
|
navLinkFocus: 'rgba(255, 255, 255, 0.75)',
|
||||||
|
navLinkActive: 'rgba(255, 255, 255, 0.9)',
|
||||||
|
borderColor: 'rgba(255, 255, 255, 0.5)',
|
||||||
|
dropdownItemColor: 'rgba(255, 255, 255, 0.7)',
|
||||||
|
dropdownItemColorHover: 'rgba(255, 255, 255, 0.9)',
|
||||||
|
commentBg: 'rgba(255, 255, 255, 0.04)',
|
||||||
|
clickToContextColor: 'rgba(255, 255, 255, 0.08)',
|
||||||
|
color: '#f8f9fa',
|
||||||
|
brandColor: 'var(--primary)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handleThemeChange = (dark) => {
|
||||||
|
const root = window.document.documentElement
|
||||||
|
const colors = COLORS[dark ? 'dark' : 'light']
|
||||||
|
Object.entries(colors).forEach(([varName, value]) => {
|
||||||
|
const cssVarName = `--theme-${varName}`
|
||||||
|
root.style.setProperty(cssVarName, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
(function () {
|
||||||
|
// Change these if you use something different in your hook.
|
||||||
|
const storageKey = 'darkMode'
|
||||||
|
|
||||||
|
const preferDarkQuery = '(prefers-color-scheme: dark)'
|
||||||
|
const mql = window.matchMedia(preferDarkQuery)
|
||||||
|
const supportsColorSchemeQuery = mql.media === preferDarkQuery
|
||||||
|
let localStorageTheme = null
|
||||||
|
try {
|
||||||
|
localStorageTheme = localStorage.getItem(storageKey)
|
||||||
|
} catch (err) {}
|
||||||
|
const localStorageExists = localStorageTheme !== null
|
||||||
|
if (localStorageExists) {
|
||||||
|
localStorageTheme = JSON.parse(localStorageTheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the source of truth
|
||||||
|
if (localStorageExists) {
|
||||||
|
// source of truth from localStorage
|
||||||
|
handleThemeChange(localStorageTheme)
|
||||||
|
} else if (supportsColorSchemeQuery) {
|
||||||
|
// source of truth from system
|
||||||
|
handleThemeChange(mql.matches)
|
||||||
|
localStorage.setItem(storageKey, mql.matches)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
@ -60,12 +60,103 @@ $tooltip-bg: #5c8001;
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5, white);
|
background: var(--theme-body);
|
||||||
background-attachment:fixed;
|
color: var(--theme-color);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
||||||
|
color: inherit;
|
||||||
|
background-color: var(--theme-inputBg);
|
||||||
|
border-color: var(--theme-borderColor);
|
||||||
|
border-bottom-color: var(--theme-inputBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
background-color: var(--theme-inputBg);
|
||||||
|
color: var(--theme-color);
|
||||||
|
border-color: var(--theme-borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
background-color: var(--theme-inputBg);
|
||||||
|
color: var(--theme-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:disabled, .form-control[readonly] {
|
||||||
|
background-color: var(--theme-inputBg);
|
||||||
|
border-color: var(--theme-borderColor);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickToContext {
|
||||||
|
border-radius: .4rem;
|
||||||
|
padding: .2rem 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickToContext:hover {
|
||||||
|
background-color: var(--theme-clickToContextColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fresh {
|
||||||
|
background-color: var(--theme-clickToContextColor);
|
||||||
|
border-radius: .4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: var(--theme-body);
|
||||||
|
border-color: var(--theme-borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .nav-link:not(.text-success) {
|
||||||
|
color: var(--theme-navLink) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .nav-link:not(.text-success):hover, .navbar-nav .nav-link:not(.text-success):focus {
|
||||||
|
color: var(--theme-navLinkFocus) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .btn-link {
|
||||||
|
color: var(--theme-navLink) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .btn-link[aria-expanded="true"] {
|
||||||
|
color: var(--theme-navLinkFocus) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .dropdown-menu {
|
||||||
|
background-color: var(--theme-body);
|
||||||
|
border: 1px solid var(--theme-borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .dropdown-item {
|
||||||
|
color: var(--theme-dropdownItemColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .dropdown-item:hover {
|
||||||
|
color: var(--theme-dropdownItemColorHover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .dropdown-item.active {
|
||||||
|
color: var(--theme-brandColor);
|
||||||
|
text-shadow: 0 0 10px var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav .dropdown-divider {
|
||||||
|
border-top: 1px solid var(--theme-borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme {
|
||||||
|
cursor: pointer;
|
||||||
|
fill: var(--theme-dropdownItemColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme:hover {
|
||||||
|
fill: var(--theme-dropdownItemColorHover);
|
||||||
|
}
|
||||||
|
|
||||||
#__next {
|
#__next {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -143,14 +234,6 @@ footer {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-dropdown-toggle .btn-link {
|
|
||||||
color: rgba(0, 0, 0, 0.5) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-dropdown-toggle .btn-link[aria-expanded="true"] {
|
|
||||||
color: rgba(0, 0, 0, 0.9) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-dropdown-toggle .dropdown .btn {
|
.nav-dropdown-toggle .dropdown .btn {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
@ -200,6 +283,10 @@ footer {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-link.active:not(.text-success) {
|
||||||
|
color: var(--theme-navLinkActive) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.fill-grey {
|
.fill-grey {
|
||||||
fill: grey;
|
fill: grey;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user