diff --git a/package.json b/package.json index ec999712..8196898d 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@loadable/babel-plugin": "^5.13.2", "@loadable/component": "^5.15.0", "@loadable/server": "^5.15.1", + "@react-spring/web": "^9.4.2", "@reduxjs/toolkit": "^1.2.2", "@sentry/browser": "^5.11.1", "@svgr/webpack": "4.3.3", @@ -46,10 +47,10 @@ "@types/react-toastify": "^4.1.0", "@types/react-virtualized": "^9.21.8", "@types/sanitize-html": "^1.20.2", - "@types/styled-components": "^4.4.1", + "@types/styled-components": "^5.1.21", "@types/throttle-debounce": "^2.1.0", - "@typescript-eslint/eslint-plugin": "^2.8.0", - "@typescript-eslint/parser": "^2.8.0", + "@typescript-eslint/eslint-plugin": "^4.1.1", + "@typescript-eslint/parser": "^4.1.1", "apollo-boost": "^0.4.7", "apollo-link": "^1.2.13", "aws-lambda": "^1.0.4", @@ -119,7 +120,7 @@ "react-outside-click-handler": "^1.3.0", "react-redux": "^7.1.3", "react-router-dom": "^5.1.2", - "react-spring": "^8.0.27", + "react-spring": "^9.4.2", "react-textarea-autosize": "^7.1.2", "react-toastify": "^5.5.0", "react-use": "^13.12.2", @@ -145,12 +146,12 @@ "snakecase-keys": "^3.1.0", "strip-markdown": "^3.1.1", "style-loader": "1.0.0", - "styled-components": "^4.4.1", + "styled-components": "^5.3.3", "terser-webpack-plugin": "2.2.1", "throttle-debounce": "^2.1.0", "ts-pnp": "1.1.5", "typesafe-actions": "^5.1.0", - "typescript": "~3.7.2", + "typescript": "^4.5.5", "unist-util-visit": "^2.0.1", "url-loader": "2.3.0", "webpack": "4.41.2", diff --git a/public/index.html b/public/index.html index e681d654..7cd045a5 100644 --- a/public/index.html +++ b/public/index.html @@ -38,6 +38,19 @@ gtag('config', 'UA-125599395-1'); + React App diff --git a/src/App.tsx b/src/App.tsx index c4686ae0..035583d3 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import NotFoundPage from './pages/NotFoundPage'; import { Helmet } from 'react-helmet-async'; import HomePage from './pages/home/HomePage'; import MainPageTemplate from './components/main/MainPageTemplate'; +import { useThemeEffect } from './components/base/hooks/useThemeEffect'; const loadableConfig = { fallback: , diff --git a/src/GlobalStyles.ts b/src/GlobalStyles.ts index 5fc987f9..74c55bde 100644 --- a/src/GlobalStyles.ts +++ b/src/GlobalStyles.ts @@ -1,4 +1,5 @@ import { createGlobalStyle } from 'styled-components'; +import { themedPalette, themes } from './lib/styles/themes'; const GlobalStyles = createGlobalStyle` body { @@ -7,8 +8,9 @@ body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Apple SD Gothic Neo", "Malgun Gothic", "맑은 고딕", 나눔고딕, "Nanum Gothic", "Noto Sans KR", "Noto Sans CJK KR", arial, 돋움, Dotum, Tahoma, Geneva, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - color: #212529; + color: ${themedPalette.text1}; box-sizing: border-box; + background: ${themedPalette.bg_page2}; } * { @@ -27,6 +29,26 @@ input, button, textarea { html, body, #root { height: 100%; } + +body { + background: ${themedPalette.bg_page2}; + ${themes.light} +} + +@media (prefers-color-scheme: dark) { + body { + ${themes.dark} + } +} + +body[data-theme='light'] { + ${themes.light}; +} + +body[data-theme='dark'] { + ${themes.dark}; +} + `; export default GlobalStyles; diff --git a/src/components/auth/AuthEmailForm.tsx b/src/components/auth/AuthEmailForm.tsx index 87deb1f6..360919f2 100644 --- a/src/components/auth/AuthEmailForm.tsx +++ b/src/components/auth/AuthEmailForm.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const AuthEmailFormBlock = styled.form` @@ -12,18 +13,24 @@ const AuthEmailFormBlock = styled.form` border-bottom-left-radius: 2px; padding: 1rem; font-size: 1rem; - border: 1px solid ${palette.gray3}; + background: ${themedPalette.bg_element1}; + border: 1px solid ${themedPalette.border3}; + color: ${themedPalette.text1}; border-right: none; + outline: none; + &:focus { + border: 1px solid ${themedPalette.primary1}; + } &::placeholder { - color: ${palette.gray6}; + color: ${themedPalette.text3}; } &:disabled { - background: ${palette.gray1}; + background: ${themedPalette.bg_element2}; } } button { - background: ${palette.teal6}; - color: white; + background: ${themedPalette.primary1}; + color: ${themedPalette.button_text}; font-size: 1rem; font-weight: bold; outline: none; @@ -35,11 +42,11 @@ const AuthEmailFormBlock = styled.form` cursor: pointer; &:hover, &:focus { - background: ${palette.teal5}; + background: ${themedPalette.primary2}; } &:disabled { - background: ${palette.gray5}; - color: ${palette.gray3}; + background: ${themedPalette.border4}; + color: ${themedPalette.text4}; cursor: default; } } @@ -62,7 +69,7 @@ const AuthEmailForm: React.FC = ({ }) => { return ( { + onSubmit={(e) => { e.preventDefault(); onSubmit(value); }} diff --git a/src/components/auth/AuthEmailSuccess.tsx b/src/components/auth/AuthEmailSuccess.tsx index 624744c3..8688e06e 100644 --- a/src/components/auth/AuthEmailSuccess.tsx +++ b/src/components/auth/AuthEmailSuccess.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled from 'styled-components'; import { MdCheck } from 'react-icons/md'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const AuthEmailSuccessBlock = styled.div` @@ -11,7 +12,7 @@ const AuthEmailSuccessBlock = styled.div` padding-left: 0.75rem; padding-right: 0.75rem; height: 3rem; - color: ${palette.teal7}; + color: ${palette.teal9}; .icon { font-size: 1.5rem; } diff --git a/src/components/auth/AuthForm.tsx b/src/components/auth/AuthForm.tsx index 7d38867e..235f2f09 100644 --- a/src/components/auth/AuthForm.tsx +++ b/src/components/auth/AuthForm.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import useInput from '../../lib/hooks/useInput'; import AuthEmailForm from './AuthEmailForm'; import { AuthMode } from '../../modules/core'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import AuthSocialButtonGroup from './AuthSocialButtonGroup'; import AuthEmailSuccess from './AuthEmailSuccess'; @@ -25,12 +26,12 @@ const AuthFormBlock = styled.div` } h2 { font-size: 1.3125rem; - color: ${palette.gray8}; + color: ${themedPalette.text1}; } h4 { margin-top: 1rem; margin-bottom: 1rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; } section + section { margin-top: 2.5rem; @@ -47,7 +48,7 @@ const AuthFormBlock = styled.div` .link { display: inline-block; font-weight: bold; - color: ${palette.teal6}; + color: ${themedPalette.primary1}; cursor: pointer; &:hover { text-decoration: underline; diff --git a/src/components/auth/AuthModal.tsx b/src/components/auth/AuthModal.tsx index 3c7128e6..8176cae4 100644 --- a/src/components/auth/AuthModal.tsx +++ b/src/components/auth/AuthModal.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; import { MdClose } from 'react-icons/md'; import zIndexes from '../../lib/styles/zIndexes'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { undrawJoyride } from '../../static/images'; import transitions from '../../lib/styles/transitions'; @@ -28,7 +29,7 @@ const AuthModalBlock = styled.div<{ visible: boolean }>` height: 100%; } - ${props => + ${(props) => props.visible ? css` animation: ${transitions.popInFromBottom} 0.4s forwards ease-in-out; @@ -44,7 +45,7 @@ const AuthModalBlock = styled.div<{ visible: boolean }>` display: none; } width: 216px; - background: ${palette.gray1}; + background: ${themedPalette.bg_element2}; padding: 1.5rem; display: flex; flex-direction: column; @@ -58,14 +59,14 @@ const AuthModalBlock = styled.div<{ visible: boolean }>` .welcome { font-size: 1.75rem; margin-top: 1.5rem; - color: ${palette.gray7}; + color: ${themedPalette.text2}; text-align: center; font-weight: 600; } } .white-block { flex: 1; - background: white; + background: ${themedPalette.bg_page2}; padding: 1.5rem; display: flex; flex-direction: column; @@ -76,7 +77,7 @@ const AuthModalBlock = styled.div<{ visible: boolean }>` display: flex; justify-content: flex-end; font-size: 1.5rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; margin-bottom: 2.25rem; svg { cursor: pointer; @@ -106,7 +107,7 @@ const AuthModal: React.FC = ({ }) => { const [closed, setClosed] = useState(true); useEffect(() => { - let timeoutId: number | null = null; + let timeoutId: ReturnType | null = null; if (visible) { setClosed(false); } else { diff --git a/src/components/auth/AuthSocialButton.tsx b/src/components/auth/AuthSocialButton.tsx index f0d899e7..4560fea7 100644 --- a/src/components/auth/AuthSocialButton.tsx +++ b/src/components/auth/AuthSocialButton.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; import { FacebookIcon, GoogleIcon, GithubIcon } from '../../static/svg'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const AuthSocialButtonBlock = styled.a<{ border: boolean }>` @@ -13,10 +14,10 @@ const AuthSocialButtonBlock = styled.a<{ border: boolean }>` outline: none; transition: 0.125s all ease-in; color: white; - ${props => + ${(props) => props.border && css` - border: 1px solid ${palette.gray3}; + border: 1px solid ${themedPalette.border3}; `} &:focus { box-shadow: 0px 2px 12px rgba(0, 0, 0, 0.35); diff --git a/src/components/auth/__tests__/__snapshots__/AuthForm.test.tsx.snap b/src/components/auth/__tests__/__snapshots__/AuthForm.test.tsx.snap index a32040bd..f4b84bfa 100644 --- a/src/components/auth/__tests__/__snapshots__/AuthForm.test.tsx.snap +++ b/src/components/auth/__tests__/__snapshots__/AuthForm.test.tsx.snap @@ -3,7 +3,7 @@ exports[`AuthForm renders correctly 1`] = `
{ + setTimeout(() => { + setEnabled(true); + }, 500); + }, []); + + if (!enabled) return null; + return ; +} + +export default BodyTransition; diff --git a/src/components/base/FloatingHeader.tsx b/src/components/base/FloatingHeader.tsx index de29a41f..8649fb1b 100644 --- a/src/components/base/FloatingHeader.tsx +++ b/src/components/base/FloatingHeader.tsx @@ -6,6 +6,7 @@ import MainResponsive from '../main/MainResponsive'; import { getScrollTop } from '../../lib/utils'; import { Route } from 'react-router-dom'; import ReadingListTab from '../readingList/ReadingListTab'; +import { themedPalette } from '../../lib/styles/themes'; export type FloatingHeaderProps = {}; @@ -107,7 +108,7 @@ function FloatingHeader(props: FloatingHeaderProps) { const Block = styled.div` position: fixed; top: 0; - background: white; + background: ${themedPalette.bg_element1}; width: 100%; z-index: 10; diff --git a/src/components/base/Header.tsx b/src/components/base/Header.tsx index 729a4a44..e4f3267e 100644 --- a/src/components/base/Header.tsx +++ b/src/components/base/Header.tsx @@ -10,6 +10,12 @@ import HeaderUserMenu from './HeaderUserMenu'; import { Link } from 'react-router-dom'; import media from '../../lib/styles/media'; import HeaderLogo from './HeaderLogo'; +import { themedPalette } from '../../lib/styles/themes'; +import ThemeToggleButton from './ThemeToggleButton'; +import { useToggleTheme } from './hooks/useToggleTheme'; +import useDidMount from '../../lib/hooks/useDidMount'; +import { useSelector } from 'react-redux'; +import { RootState } from '../../modules'; export type MainHeaderProps = {}; @@ -17,6 +23,9 @@ function Header(props: MainHeaderProps) { const { user, onLoginClick, onLogout, customHeader } = useHeader(); const [userMenu, toggleUserMenu] = useToggle(false); const ref = useRef(null); + const themeReady = useSelector( + (state: RootState) => state.darkMode.systemTheme !== 'not-ready', + ); const onOutsideClick = useCallback( (e: React.MouseEvent) => { @@ -42,6 +51,7 @@ function Header(props: MainHeaderProps) { {user ? ( + {themeReady && } @@ -67,6 +77,7 @@ function Header(props: MainHeaderProps) { ) : ( + {themeReady && } @@ -99,9 +110,10 @@ const SearchButton = styled(Link)` height: 2.5rem; outline: none; border-radius: 50%; + color: ${themedPalette.text1}; cursor: pointer; &:hover { - background: rgba(0, 0, 0, 0.045); + background: ${themedPalette.slight_layer}; } svg { width: 1.125rem; diff --git a/src/components/base/HeaderLogo.tsx b/src/components/base/HeaderLogo.tsx index e90369ba..4c763000 100644 --- a/src/components/base/HeaderLogo.tsx +++ b/src/components/base/HeaderLogo.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import { Link } from 'react-router-dom'; import { Logo, VelogIcon } from '../../static/svg'; import { UserLogo } from '../../modules/header'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { createFallbackTitle } from '../../lib/utils'; import media from '../../lib/styles/media'; @@ -48,7 +49,7 @@ const HeaderLogoBlock = styled.div` align-items: center; justify-content: center; font-weight: bold; - color: ${palette.gray8}; + color: ${themedPalette.text1}; font-size: 1.3125rem; text-decoration: none; font-family: Fira Mono, monospace; @@ -76,7 +77,9 @@ const HeaderLogoBlock = styled.div` const VelogLogoLink = styled(Link)` color: inherit; + svg { + color: inherit; margin-right: 1rem; width: 1.75rem; height: 1.75rem; diff --git a/src/components/base/HeaderUserIcon.tsx b/src/components/base/HeaderUserIcon.tsx index 61cd13ea..c423445d 100644 --- a/src/components/base/HeaderUserIcon.tsx +++ b/src/components/base/HeaderUserIcon.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import { CurrentUser } from '../../lib/graphql/user'; import { MdArrowDropDown } from 'react-icons/md'; import { userThumbnail } from '../../static/images'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import optimizeImage from '../../lib/optimizeImage'; @@ -20,7 +21,7 @@ const HeaderUserIconBlock = styled.div` svg { font-size: 1.5rem; margin-left: 0.25rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; transition: 0.125s all ease-in; margin-right: -0.4375rem; } @@ -31,7 +32,7 @@ const HeaderUserIconBlock = styled.div` box-shadow: 0px 0 12px rgba(0, 0, 0, 0.1); } svg { - color: ${palette.gray9}; + color: ${themedPalette.text1}; } } `; diff --git a/src/components/base/HeaderUserMenu.tsx b/src/components/base/HeaderUserMenu.tsx index 1ef27db1..fd85a152 100644 --- a/src/components/base/HeaderUserMenu.tsx +++ b/src/components/base/HeaderUserMenu.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import OutsideClickHandler from 'react-outside-click-handler'; import HeaderUserMenuItem from './HeaderUserMenuItem'; import media from '../../lib/styles/media'; +import { themedPalette } from '../../lib/styles/themes'; const HeaderUserMenuBlock = styled.div` position: absolute; @@ -13,7 +14,7 @@ const HeaderUserMenuBlock = styled.div` position: relative; z-index: 5; width: 12rem; - background: white; + background: ${themedPalette.bg_element1}; box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.1); .mobile-only { diff --git a/src/components/base/HeaderUserMenuItem.tsx b/src/components/base/HeaderUserMenuItem.tsx index ef8da664..46b8e197 100644 --- a/src/components/base/HeaderUserMenuItem.tsx +++ b/src/components/base/HeaderUserMenuItem.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled from 'styled-components'; import { Link } from 'react-router-dom'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const WrapperLink = styled(Link)` @@ -10,13 +11,14 @@ const WrapperLink = styled(Link)` `; const HeaderUserMenuItemBlock = styled.div` - color: ${palette.gray9}; + color: ${themedPalette.text1}; padding: 0.75rem 1rem; line-height: 1.5; font-weight: 500; cursor: pointer; &:hover { - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; + color: ${themedPalette.primary1}; } `; diff --git a/src/components/base/ThemeToggleButton.tsx b/src/components/base/ThemeToggleButton.tsx new file mode 100644 index 00000000..e357fb08 --- /dev/null +++ b/src/components/base/ThemeToggleButton.tsx @@ -0,0 +1,88 @@ +import React, { useState } from 'react'; +import { animated, useTransition } from 'react-spring'; +import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; +import { MoonIcon, SunIcon } from '../../static/svg'; +import { useToggleTheme } from './hooks/useToggleTheme'; + +interface Props {} + +function ThemeToggleButton(props: Props) { + const [theme, toggle] = useToggleTheme(); + + const isDark = theme === 'dark'; + const transitions = useTransition(isDark, { + initial: { + transform: 'scale(1) rotate(0deg)', + opacity: 1, + }, + from: { + transform: 'scale(0) rotate(-180deg)', + opacity: 0, + }, + enter: { + transform: 'scale(1) rotate(0deg)', + opacity: 1, + }, + leave: { + transform: 'scale(0) rotate(180deg)', + opacity: 0, + }, + + reverse: true, + }); + + return ( + + {transitions((style, item) => + item ? ( + + + + + + ) : ( + + + + + + ), + )} + + ); +} + +const IconButton = styled.button` + background: none; + border: none; + cursor: pointer; + border-radius: 50%; + width: 2.5rem; + height: 2.5rem; + margin-right: 0.75rem; + color: white; + position: relative; + + &:hover { + background: ${themedPalette.slight_layer}; + } +`; + +const Positioner = styled.div` + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +`; + +const SVGWrapper = styled.div` + color: ${themedPalette.text1}; + svg { + display: block; + } +`; + +const AnimatedSVGWrapper = animated(SVGWrapper); + +export default ThemeToggleButton; diff --git a/src/components/base/__tests__/__snapshots__/HeaderUserIcon.test.tsx.snap b/src/components/base/__tests__/__snapshots__/HeaderUserIcon.test.tsx.snap index 30a92abc..6890366f 100644 --- a/src/components/base/__tests__/__snapshots__/HeaderUserIcon.test.tsx.snap +++ b/src/components/base/__tests__/__snapshots__/HeaderUserIcon.test.tsx.snap @@ -3,7 +3,7 @@ exports[`HeaderUserIcon matches snapshot 1`] = `
thumbnail state.darkMode.theme); + + useEffect(() => { + const systemPrefersDark = window.matchMedia( + '(prefers-color-scheme: dark)', + ).matches; + dispatch( + darkMode.actions.setSystemTheme(systemPrefersDark ? 'dark' : 'light'), + ); + }, [dispatch]); + + useEffect(() => { + if (theme !== 'default') { + document.body.dataset.theme = theme; + } + }, [theme]); +} diff --git a/src/components/base/hooks/useToggleTheme.ts b/src/components/base/hooks/useToggleTheme.ts new file mode 100644 index 00000000..4552be6c --- /dev/null +++ b/src/components/base/hooks/useToggleTheme.ts @@ -0,0 +1,28 @@ +import { useDispatch } from 'react-redux'; +import { useTheme } from '../../../lib/hooks/useTheme'; +import storage from '../../../lib/storage'; +import darkMode from '../../../modules/darkMode'; + +export function useToggleTheme() { + const dispatch = useDispatch(); + const theme = useTheme(); + + const saveToStorage = (value: 'light' | 'dark') => { + storage.setItem('theme', value); // For CSR + // save to cookie + document.cookie = `theme=${value}; path=/;`; // For SSR + }; + + const toggle = () => { + if (!theme) return; + if (theme === 'dark') { + dispatch(darkMode.actions.enableLightMode()); + saveToStorage('light'); + } else { + dispatch(darkMode.actions.enableDarkMode()); + saveToStorage('dark'); + } + }; + + return [theme, toggle] as const; +} diff --git a/src/components/common/AdFeed.tsx b/src/components/common/AdFeed.tsx index af561225..1ed57076 100644 --- a/src/components/common/AdFeed.tsx +++ b/src/components/common/AdFeed.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react'; import styled from 'styled-components'; import { mediaQuery } from '../../lib/styles/media'; import gtag from '../../lib/gtag'; +import { themedPalette } from '../../lib/styles/themes'; function AdFeed({ forPost, index }: { forPost?: boolean; index: number }) { const ref = useRef(null); @@ -104,7 +105,7 @@ const Block = styled.div<{ forPost?: boolean }>` height: auto; border-radius: 4px; box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.04); - background: white; + background: ${themedPalette.bg_element1}; ${mediaQuery(1056)} { width: calc(50% - 2rem); diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index 20ef148e..12b42359 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; import palette, { buttonColorMap } from '../../lib/styles/palette'; import media from '../../lib/styles/media'; +import { themedPalette } from '../../lib/styles/themes'; type ColorType = | 'teal' @@ -26,16 +27,16 @@ const ButtonBlock = styled.button<{ outline: none; border: none; color: white; - background: ${props => buttonColorMap[props.color].background}; - color: ${props => buttonColorMap[props.color].color}; + background: ${(props) => buttonColorMap[props.color].background}; + color: ${(props) => buttonColorMap[props.color].color}; &:hover, &:focus { - background: ${props => buttonColorMap[props.color].hoverBackground}; + background: ${(props) => buttonColorMap[props.color].hoverBackground}; } border-radius: 4px; padding-top: 0; padding-bottom: 0; - ${props => + ${(props) => props.inline && css` & + & { @@ -43,7 +44,7 @@ const ButtonBlock = styled.button<{ } `} - ${props => + ${(props) => props.responsive && css` ${media.small} { @@ -54,7 +55,7 @@ const ButtonBlock = styled.button<{ } `} - ${props => + ${(props) => props.size === 'medium' && css` height: 2rem; @@ -63,27 +64,27 @@ const ButtonBlock = styled.button<{ font-size: 1rem; `} - ${props => - props.size === 'large' && - css` - height: 2.5rem; - padding-left: 1.125rem; - padding-right: 1.125rem; - & + & { - margin-left: 0.875rem; - } - font-size: 1.125rem; - `} + ${(props) => + props.size === 'large' && + css` + height: 2.5rem; + padding-left: 1.125rem; + padding-right: 1.125rem; + & + & { + margin-left: 0.875rem; + } + font-size: 1.125rem; + `} &:disabled { - cursor: not-allowed; - background: ${palette.gray3}; - color: ${palette.gray5}; - &:hover { - background: ${palette.gray3}; - color: ${palette.gray5}; - } + cursor: not-allowed; + background: ${themedPalette.bg_element4}; + color: ${themedPalette.text3}; + &:hover { + background: ${themedPalette.bg_element4}; + color: ${themedPalette.text3}; } + } `; interface ButtonProps extends Omit, 'size'> { @@ -110,7 +111,7 @@ const Button: React.FC = ({ size={size} responsive={responsive} {...htmlProps} - onClick={e => { + onClick={(e) => { if (htmlProps.onClick) { htmlProps.onClick(e); } diff --git a/src/components/common/EditRemoveGroup.tsx b/src/components/common/EditRemoveGroup.tsx index f9f56825..573f1203 100644 --- a/src/components/common/EditRemoveGroup.tsx +++ b/src/components/common/EditRemoveGroup.tsx @@ -1,4 +1,5 @@ import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const EditRemoveGroup = styled.div` @@ -9,9 +10,9 @@ const EditRemoveGroup = styled.div` background: none; font-size: inherit; cursor: pointer; - color: ${palette.gray6}; + color: ${themedPalette.text3}; &:hover { - color: ${palette.gray9}; + color: ${themedPalette.text1}; } } button + button { diff --git a/src/components/common/FlatPostCard.tsx b/src/components/common/FlatPostCard.tsx index 4a0a1e5b..d3718287 100644 --- a/src/components/common/FlatPostCard.tsx +++ b/src/components/common/FlatPostCard.tsx @@ -1,6 +1,7 @@ import React, { useRef } from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { userThumbnail } from '../../static/images'; import Tag from './TagItem'; @@ -37,7 +38,7 @@ const PostCardBlock = styled.div` height: 3rem; display: block; margin-right: 1rem; - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; object-fit: cover; border-radius: 1.5rem; box-shadow: 0px 0 8px rgba(0, 0, 0, 0.1); @@ -49,13 +50,13 @@ const PostCardBlock = styled.div` } .username { font-size: 0.875rem; - color: ${palette.gray9}; + color: ${themedPalette.text1}; font-weight: bold; a { color: inherit; text-decoration: none; &:hover { - color: ${palette.gray8}; + color: ${themedPalette.text1}; } } } @@ -73,7 +74,7 @@ const PostCardBlock = styled.div` h2 { font-size: 1.5rem; margin: 0; - color: ${palette.gray9}; + color: ${themedPalette.text1}; word-break: keep-all; ${media.small} { font-size: 1rem; @@ -83,7 +84,7 @@ const PostCardBlock = styled.div` margin-bottom: 2rem; margin-top: 0.5rem; font-size: 1rem; - color: ${palette.gray7}; + color: ${themedPalette.text2}; word-break: keep-all; overflow-wrap: break-word; ${media.small} { @@ -95,7 +96,7 @@ const PostCardBlock = styled.div` display: flex; align-items: center; margin-top: 1rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; font-size: 0.875rem; ${media.small} { font-size: 0.75rem; @@ -115,7 +116,7 @@ const PostCardBlock = styled.div` } & + & { - border-top: 1px solid ${palette.gray2}; + border-top: 1px solid ${themedPalette.border4}; } `; @@ -126,7 +127,7 @@ interface PostCardProps { const FlatPostCard = ({ post, hideUser }: PostCardProps) => { const prefetch = usePrefetchPost(post.user.username, post.url_slug); - const prefetchTimeoutId = useRef(null); + const prefetchTimeoutId = useRef | null>(null); const onMouseEnter = () => { prefetchTimeoutId.current = setTimeout(prefetch, 2000); @@ -178,7 +179,7 @@ const FlatPostCard = ({ post, hideUser }: PostCardProps) => {

{post.short_description}

- {post.tags.map(tag => ( + {post.tags.map((tag) => ( ))}
diff --git a/src/components/common/FlatPostCardList.tsx b/src/components/common/FlatPostCardList.tsx index 4d6cc919..7ed533b5 100644 --- a/src/components/common/FlatPostCardList.tsx +++ b/src/components/common/FlatPostCardList.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled from 'styled-components'; import PostCard, { PostCardSkeleton } from './FlatPostCard'; import { PartialPost } from '../../lib/graphql/post'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const PostCardListBlock = styled.div``; @@ -14,7 +15,7 @@ interface PostCardListProps { const PostCardList: React.FC = ({ posts, hideUser }) => { return ( - {posts.map(post => ( + {posts.map((post) => ( ))} @@ -41,7 +42,7 @@ export function PostCardListSkeleton({ } const Separator = styled.div` - border-top: 1px solid ${palette.gray2}; + border-top: 1px solid ${themedPalette.border4}; `; export default PostCardList; diff --git a/src/components/common/HorizontalTab.tsx b/src/components/common/HorizontalTab.tsx index 895a8d19..8e6d3251 100644 --- a/src/components/common/HorizontalTab.tsx +++ b/src/components/common/HorizontalTab.tsx @@ -1,6 +1,7 @@ import React from 'react'; import styled, { css } from 'styled-components'; import { Link } from 'react-router-dom'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { useSpring, animated } from 'react-spring'; import media from '../../lib/styles/media'; @@ -23,7 +24,7 @@ function HorizontalTab({ theme, }: HorizontalTabProps) { const activeIndex = React.Children.toArray(children).findIndex( - tab => tab.props.name === activeTab, + (tab) => tab.props.name === activeTab, ); const ratio = 100 / children.length; @@ -40,7 +41,7 @@ function HorizontalTab({ return (
- {React.Children.map(children, tab => { + {React.Children.map(children, (tab) => { return React.cloneElement(tab, { active: tab.props.name === activeTab, width: `${tabWidth}rem`, @@ -87,7 +88,7 @@ TabItem.defaultProps = { const Block = styled.div<{ align: 'center' | 'left' }>` display: flex; - ${props => + ${(props) => props.align === 'center' && css` justify-content: center; @@ -103,11 +104,11 @@ const Indicator = styled(animated.div)<{ theme: 'teal' | 'gray' }>` display: block; position: absolute; bottom: 0px; - background: ${palette.teal5}; - ${props => + background: ${themedPalette.primary2}; + ${(props) => props.theme === 'gray' && css` - background: ${palette.gray8}; + background: ${themedPalette.border1}; `} `; @@ -120,7 +121,7 @@ const StyledLink = styled(Link)<{ ${media.small} { font-size: 1rem; } - color: ${palette.gray6}; + color: ${themedPalette.text3}; display: flex; align-items: center; justify-content: center; @@ -128,11 +129,11 @@ const StyledLink = styled(Link)<{ &.active { font-weight: bold; - color: ${palette.teal5}; - ${props => + color: ${themedPalette.primary2}; + ${(props) => props.theme === 'gray' && css` - color: ${palette.gray8}; + color: ${themedPalette.text1}; `} } `; diff --git a/src/components/common/LabelInput.tsx b/src/components/common/LabelInput.tsx index 0cac9fc4..afa89aca 100644 --- a/src/components/common/LabelInput.tsx +++ b/src/components/common/LabelInput.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { MdLockOutline } from 'react-icons/md'; import media from '../../lib/styles/media'; @@ -12,17 +13,18 @@ const LabelInputBlock = styled.div<{ focus: boolean }>` label { font-weight: bold; font-size: 1.125rem; - color: ${palette.gray9}; + color: ${themedPalette.text1}; margin-bottom: 1rem; transition: all 0.125s ease-in; - ${props => + ${(props) => props.focus && css` - color: ${palette.teal7}; + color: ${themedPalette.primary1}; `} } input { + background: transparent; font-size: 1.5rem; border: none; outline: none; @@ -31,18 +33,18 @@ const LabelInputBlock = styled.div<{ focus: boolean }>` } width: 100%; - color: ${palette.gray7}; + color: ${themedPalette.text2}; transition: all 0.125s ease-in; - ${props => + ${(props) => props.focus && css` - color: ${palette.teal7}; + color: ${themedPalette.primary1}; `} &::placeholder { - color: ${palette.gray5}; + color: ${themedPalette.text3}; } &:disabled { - color: ${palette.gray6}; + color: ${themedPalette.text3}; } } .group { @@ -51,20 +53,20 @@ const LabelInputBlock = styled.div<{ focus: boolean }>` } .input-wrapper { padding-bottom: 0.5rem; - border-bottom: 1px solid ${palette.gray7}; + border-bottom: 1px solid ${themedPalette.border2}; display: flex; align-items: center; - ${props => + ${(props) => props.focus && css` - border-color: ${palette.teal7}; + border-color: ${themedPalette.primary1}; `} input { width: 1; } svg { font-size: 1.5rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; } } .width-maker { diff --git a/src/components/common/MarkdownEditor.tsx b/src/components/common/MarkdownEditor.tsx index 4f428fdf..1424f31c 100644 --- a/src/components/common/MarkdownEditor.tsx +++ b/src/components/common/MarkdownEditor.tsx @@ -2,22 +2,25 @@ import React, { CSSProperties, useRef, useEffect, useCallback } from 'react'; import styled from 'styled-components'; import CodeMirror, { EditorFromTextArea, Editor } from 'codemirror'; import './atom-one-light.css'; +import './atom-one-dark.css'; import 'codemirror/lib/codemirror.css'; -import palette from '../../lib/styles/palette'; +import { themedPalette } from '../../lib/styles/themes'; + import 'codemirror/mode/markdown/markdown'; import 'codemirror/addon/display/placeholder'; +import { useTheme } from '../../lib/hooks/useTheme'; const MarkdownEditorBlock = styled.div` .CodeMirror { height: auto; font-size: 1.125rem; line-height: 1.5; - color: ${palette.gray8}; + color: ${themedPalette.text1}; font-family: 'Fira Mono', monospace; /* font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', */ .cm-header { line-height: 2; - color: ${palette.gray9}; + color: ${themedPalette.text1}; } .cm-header-1 { font-size: 2.5rem; @@ -35,10 +38,10 @@ const MarkdownEditorBlock = styled.div` } .cm-strong, .cm-em { - color: ${palette.gray9}; + color: ${themedPalette.text1}; } .CodeMirror-placeholder { - color: ${palette.gray5}; + color: ${themedPalette.text3}; font-style: italic; } } @@ -67,12 +70,14 @@ const MarkdownEditor = ({ [onChangeMarkdown], ); + const theme = useTheme(); + // initialize editor useEffect(() => { if (!textArea.current) return; const cm = CodeMirror.fromTextArea(textArea.current, { mode: 'markdown', - theme: 'one-light', + theme: `one-${theme}`, placeholder: '당신은 어떤 사람인가요? 당신에 대해서 알려주세요.', lineWrapping: true, }); diff --git a/src/components/common/MarkdownRender.tsx b/src/components/common/MarkdownRender.tsx index 2c0207c6..35c796c5 100644 --- a/src/components/common/MarkdownRender.tsx +++ b/src/components/common/MarkdownRender.tsx @@ -31,11 +31,8 @@ export interface MarkdownRenderProps { } const MarkdownRenderBlock = styled.div` - &.atom-one-dark { - ${prismThemes['atom-one-dark']} - } - &.atom-one-light { - ${prismThemes['atom-one-light']} + &.atom-one { + ${prismThemes['atom-one']} } &.github { ${prismThemes['github']} @@ -203,7 +200,7 @@ type RenderedElement = const MarkdownRender: React.FC = ({ markdown, - codeTheme = 'atom-one-light', + codeTheme = 'atom-one', onConvertFinish, editing, }) => { diff --git a/src/components/common/OpaqueLayer.tsx b/src/components/common/OpaqueLayer.tsx index 5a2f6330..8a28a799 100644 --- a/src/components/common/OpaqueLayer.tsx +++ b/src/components/common/OpaqueLayer.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import transitions from '../../lib/styles/transitions'; import zIndexes from '../../lib/styles/zIndexes'; @@ -12,10 +13,10 @@ const OpaqueLayerBlock = styled.div<{ left: 0; width: 100%; height: 100%; - background: rgba(249, 249, 249, 0.85); + background: ${themedPalette.opaque_layer}; z-index: ${zIndexes.OpaqueLayer}; - ${props => + ${(props) => props.visible ? css` animation: ${transitions.fadeIn} 0.25s forwards; @@ -33,7 +34,7 @@ const { useState, useEffect, useRef } = React; const OpaqueLayer: React.FC = ({ visible }) => { const [animate, setAnimate] = useState(false); - const timeoutId = useRef(null); + const timeoutId = useRef | null>(null); const mounted = useRef(false); const [closed, setClosed] = useState(true); diff --git a/src/components/common/PopupBase.tsx b/src/components/common/PopupBase.tsx index 34f92219..642857b2 100644 --- a/src/components/common/PopupBase.tsx +++ b/src/components/common/PopupBase.tsx @@ -4,6 +4,7 @@ import OpaqueLayer from './OpaqueLayer'; import zIndexes from '../../lib/styles/zIndexes'; import transitions from '../../lib/styles/transitions'; import media from '../../lib/styles/media'; +import { themedPalette } from '../../lib/styles/themes'; const PopupBaseBlock = styled.div` position: fixed; @@ -20,13 +21,13 @@ const PopupBaseBlock = styled.div` const PopupWrapper = styled.div<{ visible: boolean }>` width: 25rem; border-radius: 4px; - background: white; + background: ${themedPalette.bg_element1}; padding: 2rem 1.5rem; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.09); ${media.small} { width: calc(100% - 2rem); } - ${props => + ${(props) => props.visible ? css` animation: ${transitions.popInFromBottom} 0.4s forwards ease-in-out; @@ -45,7 +46,7 @@ const { useState, useEffect } = React; const PopupBase: React.FC = ({ visible, children }) => { const [closed, setClosed] = useState(true); useEffect(() => { - let timeoutId: number | null = null; + let timeoutId: ReturnType | null = null; if (visible) { setClosed(false); } else { diff --git a/src/components/common/PopupOKCancel.tsx b/src/components/common/PopupOKCancel.tsx index 3b40218d..9b574db4 100644 --- a/src/components/common/PopupOKCancel.tsx +++ b/src/components/common/PopupOKCancel.tsx @@ -2,20 +2,21 @@ import * as React from 'react'; import styled from 'styled-components'; import PopupBase from './PopupBase'; import Button from './Button'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const PopupOKCancelBlock = styled.div` h3 { margin: 0; font-size: 1.5rem; - color: ${palette.gray8}; + color: ${themedPalette.text1}; line-height: 1.5; font-weight: bold; } .message { line-height: 1.5; font-size: 1rem; - color: ${palette.gray7}; + color: ${themedPalette.text2}; margin-top: 1rem; margin-bottom: 1rem; white-space: pre-wrap; @@ -52,7 +53,7 @@ const PopupOKCancel: React.FC = ({
{children}
{onCancel && ( - )} diff --git a/src/components/common/PostCard.tsx b/src/components/common/PostCard.tsx index 053dcbb7..bde7d6ab 100644 --- a/src/components/common/PostCard.tsx +++ b/src/components/common/PostCard.tsx @@ -2,6 +2,7 @@ import React, { useRef } from 'react'; import styled, { css } from 'styled-components'; import RatioImage from './RatioImage'; import { ellipsis } from '../../lib/styles/utils'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { LikeIcon } from '../../static/svg'; import { PartialPost } from '../../lib/graphql/post'; @@ -25,7 +26,7 @@ function PostCard({ post, forHome, forPost }: PostCardProps) { const url = `/@${post.user.username}/${post.url_slug}`; const prefetch = usePrefetchPost(post.user.username, post.url_slug); - const prefetchTimeoutId = useRef(null); + const prefetchTimeoutId = useRef | null>(null); const onMouseEnter = () => { prefetchTimeoutId.current = setTimeout(prefetch, 2000); @@ -106,7 +107,7 @@ export function PostCardSkeleton({
- +

@@ -155,7 +156,7 @@ const StyledLink = styled(Link)` const Block = styled.div<{ forHome: boolean; forPost: boolean }>` width: 20rem; - background: white; + background: ${themedPalette.bg_element1}; border-radius: 4px; box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.04); transition: 0.25s box-shadow ease-in, 0.25s transform ease-in; @@ -195,7 +196,7 @@ const Block = styled.div<{ forHome: boolean; forPost: boolean }>` } `; -const Content = styled.div<{ clamp: boolean }>` +const Content = styled.div<{ clamp: boolean; isSkeleton?: boolean }>` padding: 1rem; display: flex; flex: 1; @@ -206,8 +207,14 @@ const Content = styled.div<{ clamp: boolean }>` margin-bottom: 0.25rem; line-height: 1.5; word-break: break-word; + ${ellipsis} - color: ${palette.gray9}; + ${(props) => + props.isSkeleton && + css` + text-overflow: initial; + `} + color: ${themedPalette.text1}; ${mediaQuery(767)} { white-space: initial; } @@ -237,13 +244,13 @@ const Content = styled.div<{ clamp: boolean }>` height: 15.875rem; `} */ - color: ${palette.gray7}; + color: ${themedPalette.text2}; margin-bottom: 1.5rem; } .sub-info { font-size: 0.75rem; line-height: 1.5; - color: ${palette.gray6}; + color: ${themedPalette.text3}; .separator { margin-left: 0.25rem; margin-right: 0.25rem; @@ -253,7 +260,7 @@ const Content = styled.div<{ clamp: boolean }>` const Footer = styled.div` padding: 0.625rem 1rem; - border-top: 1px solid ${palette.gray0}; + border-top: 1px solid ${themedPalette.border4}; display: flex; font-size: 0.75rem; line-height: 1.5; @@ -272,9 +279,9 @@ const Footer = styled.div` margin-right: 0.5rem; } span { - color: ${palette.gray6}; + color: ${themedPalette.text3}; b { - color: ${palette.gray8}; + color: ${themedPalette.text1}; } } } diff --git a/src/components/common/PrivatePostLabel.tsx b/src/components/common/PrivatePostLabel.tsx index 8a786217..4cfe6e9d 100644 --- a/src/components/common/PrivatePostLabel.tsx +++ b/src/components/common/PrivatePostLabel.tsx @@ -1,5 +1,6 @@ import React from 'react'; import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { LockIcon } from '../../static/svg'; diff --git a/src/components/common/RequireLogin.tsx b/src/components/common/RequireLogin.tsx index 82cdbc0a..84175f56 100644 --- a/src/components/common/RequireLogin.tsx +++ b/src/components/common/RequireLogin.tsx @@ -3,6 +3,7 @@ import { undrawLogin } from '../../static/images'; import styled, { css } from 'styled-components'; import Button from './Button'; import useRequireLogin from '../../lib/hooks/useRequireLogin'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import media from '../../lib/styles/media'; @@ -38,13 +39,13 @@ const Block = styled.div<{ hasMargin?: boolean }>` } h2 { font-weight: 400; - color: ${palette.gray8}; + color: ${themedPalette.text1}; margin-top: 2rem; ${media.small} { font-size: 1.25rem; } } - ${props => + ${(props) => props.hasMargin && css` margin-top: 10rem; diff --git a/src/components/common/RoundButton.tsx b/src/components/common/RoundButton.tsx index eb17f6be..58550ac6 100644 --- a/src/components/common/RoundButton.tsx +++ b/src/components/common/RoundButton.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; import { buttonColorMap } from '../../lib/styles/palette'; import { Route } from 'react-router'; +import { themedPalette } from '../../lib/styles/themes'; type ButtonSize = 'SMALL' | 'DEFAULT' | 'LARGE'; @@ -13,7 +14,7 @@ type RoundButtonBlockProps = { }; const RoundButtonBlock = styled.button` - ${props => + ${(props) => props.inline && css` & + & { @@ -21,7 +22,7 @@ const RoundButtonBlock = styled.button` } `} - ${props => + ${(props) => props.size === 'SMALL' && css` height: 1.5rem; @@ -30,7 +31,7 @@ const RoundButtonBlock = styled.button` font-size: 0.875rem; border-radius: 0.75rem; `}; - ${props => + ${(props) => props.size === 'DEFAULT' && css` height: 2rem; @@ -39,7 +40,7 @@ const RoundButtonBlock = styled.button` font-size: 1rem; border-radius: 1rem; `}; - ${props => + ${(props) => props.size === 'LARGE' && css` height: 3rem; @@ -54,21 +55,21 @@ const RoundButtonBlock = styled.button` outline: none; font-weight: bold; word-break: keep-all; - background: ${props => buttonColorMap[props.color].background}; - color: ${props => buttonColorMap[props.color].color}; + background: ${(props) => buttonColorMap[props.color].background}; + color: ${(props) => buttonColorMap[props.color].color}; &:hover { - background: ${props => buttonColorMap[props.color].hoverBackground}; + background: ${(props) => buttonColorMap[props.color].hoverBackground}; } - ${props => + ${(props) => props.border && css` - background: white; - border: 1px solid ${props => buttonColorMap[props.color].background}; - color: ${props => buttonColorMap[props.color].background}; + background: ${themedPalette.bg_element2}; + border: 1px solid ${(props) => buttonColorMap[props.color].background}; + color: ${(props) => buttonColorMap[props.color].background}; &:hover { - background: ${props => buttonColorMap[props.color].background}; - color: white; + background: ${(props) => buttonColorMap[props.color].background}; + color: ${themedPalette.button_text}; } `} @@ -106,7 +107,7 @@ const RoundButton: React.FC = ({ render={({ history }) => ( { + onClick={(e) => { e.preventDefault(); history.push(to); }} diff --git a/src/components/common/SelectableList.tsx b/src/components/common/SelectableList.tsx index d1a638f1..69d13884 100644 --- a/src/components/common/SelectableList.tsx +++ b/src/components/common/SelectableList.tsx @@ -1,12 +1,13 @@ import React from 'react'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const SelectableListBlock = styled.ul` padding-left: 0; list-style: none; margin: 0; - background: white; + background: ${themedPalette.bg_element7}; overflow-y: auto; `; @@ -14,14 +15,14 @@ const ListItem = styled.li<{ active: boolean }>` padding: 0.875rem 1rem; font-size: 1rem; line-height: 1; - color: ${palette.gray7}; - border-bottom: 1px solid ${palette.gray2}; + color: ${themedPalette.text2}; + border-bottom: 1px solid ${themedPalette.border3}; - ${props => + ${(props) => props.active && css` - background: ${palette.teal6}; - color: white; + background: ${themedPalette.primary1}; + color: ${themedPalette.button_text}; `}; `; @@ -35,28 +36,27 @@ export interface SelectableListProps { onChangeId: (id: any) => void; } -const SelectableList: React.ComponentType< - SelectableListProps -> = React.forwardRef( - ( - { list, selectedId, className, onChangeId }: SelectableListProps, - ref: React.Ref, - ) => { - return ( - - {list.map(item => ( - onChangeId(item.id)} - > - {item.text} - - ))} - - ); - }, -); +const SelectableList: React.ComponentType = + React.forwardRef( + ( + { list, selectedId, className, onChangeId }: SelectableListProps, + ref: React.Ref, + ) => { + return ( + + {list.map((item) => ( + onChangeId(item.id)} + > + {item.text} + + ))} + + ); + }, + ); export default SelectableList; diff --git a/src/components/common/Skeleton.tsx b/src/components/common/Skeleton.tsx index e0f01c35..9f038769 100644 --- a/src/components/common/Skeleton.tsx +++ b/src/components/common/Skeleton.tsx @@ -1,5 +1,6 @@ import React from 'react'; import styled, { keyframes, css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; export type SkeletonProps = { @@ -46,13 +47,13 @@ const shining = keyframes` `; const Block = styled.span<{ noSpacing?: boolean; circle?: boolean }>` - background: ${palette.gray1}; + background: ${themedPalette.bg_element4}; animation: ${shining} 1s ease-in-out infinite; display: inline-block; border-radius: 4px; height: 1em; - ${props => + ${(props) => !props.noSpacing && css` & + & { @@ -60,7 +61,7 @@ const Block = styled.span<{ noSpacing?: boolean; circle?: boolean }>` } `} - ${props => + ${(props) => props.circle && css` border-radius: 50%; diff --git a/src/components/common/SorterButton.tsx b/src/components/common/SorterButton.tsx index 22baa0ef..0457d93b 100644 --- a/src/components/common/SorterButton.tsx +++ b/src/components/common/SorterButton.tsx @@ -1,6 +1,7 @@ import React from 'react'; import styled from 'styled-components'; import { MdKeyboardArrowUp } from 'react-icons/md'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const StyledButton = styled.button` @@ -10,19 +11,19 @@ const StyledButton = styled.button` padding-right: 0.75rem; align-items: center; cursor: pointer; - background: ${palette.gray1}; + background: ${themedPalette.bg_element2}; border-radius: 4px; border: none; outline: none; &:hover { - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; } &:focus { box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.12); } svg { - color: ${palette.teal5}; + color: ${themedPalette.primary2}; font-size: 1.5rem; transition: 0.125s all ease-in; &.rotate { @@ -32,7 +33,7 @@ const StyledButton = styled.button` span { margin-left: 0.25rem; font-size: 1rem; - color: ${palette.gray8}; + color: ${themedPalette.text1}; line-height: 1; } `; diff --git a/src/components/common/SpinnerBlock.tsx b/src/components/common/SpinnerBlock.tsx index 872fbcbf..b8661e4d 100644 --- a/src/components/common/SpinnerBlock.tsx +++ b/src/components/common/SpinnerBlock.tsx @@ -1,5 +1,6 @@ import React from 'react'; import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; function SpinnerBlock() { @@ -35,7 +36,7 @@ const Block = styled.div` display: block; width: 25%; height: 25%; - background-color: ${palette.teal6}; + background-color: ${themedPalette.primary1}; border-radius: 100%; animation: sk-chase-dot-before 2s infinite ease-in-out both; } diff --git a/src/components/common/TagItem.tsx b/src/components/common/TagItem.tsx index 2d6a5791..3d8fd1d9 100644 --- a/src/components/common/TagItem.tsx +++ b/src/components/common/TagItem.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { Link } from 'react-router-dom'; import { escapeForUrl } from '../../lib/utils'; @@ -19,7 +20,7 @@ const TagItem: React.FC = ({ name, link }) => { const tagStyle = css` margin-bottom: 0.875rem; - background: ${palette.gray1}; + background: ${themedPalette.bg_element2}; padding-left: 1rem; padding-right: 1rem; height: 2rem; @@ -27,7 +28,7 @@ const tagStyle = css` display: inline-flex; align-items: center; margin-right: 0.875rem; - color: ${palette.teal7}; + color: ${themedPalette.primary1}; text-decoration: none; font-weight: 500; font-size: 1rem; @@ -49,7 +50,7 @@ const TagDiv = styled.div` const TagLink = styled(Link)` ${tagStyle} &:hover { - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; } `; diff --git a/src/components/common/ToggleSwitch.tsx b/src/components/common/ToggleSwitch.tsx index 140fe10e..10c242c3 100644 --- a/src/components/common/ToggleSwitch.tsx +++ b/src/components/common/ToggleSwitch.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect, useRef } from 'react'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { useSpring, animated } from 'react-spring'; - export type ToggleSwitchProps = { name?: string; value: boolean; @@ -27,7 +27,7 @@ function ToggleSwitch({ value, name, onChange }: ToggleSwitchProps) { }); const toggle = () => { - setLocalValue(v => !v); + setLocalValue((v) => !v); }; useEffect(() => { @@ -59,20 +59,20 @@ const Block = styled.div<{ active: boolean }>` align-items: center; width: 2.875rem; height: 1.5rem; - background: ${palette.gray2}; + background: ${palette.gray6}; transition: 0.125s all ease-in; border-radius: 1.125rem; padding: 0.125rem; - ${props => + ${(props) => props.active && css` - background: ${palette.teal5}; + background: ${themedPalette.primary2}; `} .circle { width: 1.25rem; height: 1.25rem; border-radius: 0.625rem; - background: white; + background: ${themedPalette.bg_element1}; box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05); } `; diff --git a/src/components/common/Typography.tsx b/src/components/common/Typography.tsx index dd1becb8..4bdf8104 100644 --- a/src/components/common/Typography.tsx +++ b/src/components/common/Typography.tsx @@ -1,18 +1,21 @@ import * as React from 'react'; import styled from 'styled-components'; -import palette from '../../lib/styles/palette'; +import { themedPalette } from '../../lib/styles/themes'; import media from '../../lib/styles/media'; const TypographyBlock = styled.div` font-size: 1.125rem; - color: #222426; + color: ${themedPalette.text1}; + transition: color 0.125s ease-in; line-height: 1.7; letter-spacing: -0.004em; word-break: keep-all; word-wrap: break-word; - ul, ol, p { + ul, + ol, + p { /* ${media.xxlarge} { - color: ${palette.gray8}; + color: ${themedPalette.text1}; font-weight: 300; } */ @@ -20,14 +23,14 @@ const TypographyBlock = styled.div` font-weight: 400; } code { - background: rgba(27,31,35,.05); - padding: .2em .4em; + background: ${themedPalette.bg_element3}; + padding: 0.2em 0.4em; font-size: 85%; border-radius: 3px; } a { code { - color: ${palette.teal6}; + color: ${themedPalette.primary1}; } } } @@ -36,10 +39,10 @@ const TypographyBlock = styled.div` arial, 나눔고딕, 'Nanum Gothic', 돋움; */ a { - color: ${palette.teal7}; + color: ${themedPalette.primary1}; text-decoration: none; &:hover { - color: ${palette.teal6}; + color: ${themedPalette.primary1}; text-decoration: underline; } } @@ -52,7 +55,7 @@ const TypographyBlock = styled.div` border: none; height: 1px; width: 100%; - background: #dedede; + background: ${themedPalette.border3}; margin-top: 2rem; margin-bottom: 2rem; } @@ -126,16 +129,17 @@ const TypographyBlock = styled.div` blockquote { margin-top: 2rem; margin-bottom: 2rem; - border-left: 4px solid ${palette.teal5}; + border-left: 4px solid ${themedPalette.primary2}; border-top-right-radius: 4px; border-bottom-right-radius: 4px; - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; margin-left: 0; margin-right: 0; padding: 1rem; padding-left: 2rem; - color: ${palette.gray9}; - ul, ol { + color: ${themedPalette.text1}; + ul, + ol { padding-left: 1rem; } *:first-child { diff --git a/src/components/common/UserProfile.tsx b/src/components/common/UserProfile.tsx index 3fb44e2c..22b5d00d 100644 --- a/src/components/common/UserProfile.tsx +++ b/src/components/common/UserProfile.tsx @@ -1,5 +1,6 @@ import React, { CSSProperties, useState, useRef } from 'react'; import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { GithubIcon, @@ -57,12 +58,12 @@ const UserInfo = styled.div` font-size: 1.5rem; line-height: 1.5; font-weight: bold; - color: ${palette.gray9}; + color: ${themedPalette.text1}; a { color: inherit; text-decoration: none; &:hover { - color: ${palette.gray8}; + color: ${themedPalette.text1}; text-decoration: underline; } } @@ -72,7 +73,7 @@ const UserInfo = styled.div` font-size: 1.125rem; line-height: 1.5; margin-top: 0.25rem; - color: ${palette.gray7}; + color: ${themedPalette.text2}; letter-spacing: -0.004em; } @@ -92,7 +93,7 @@ const UserInfo = styled.div` `; const Separator = styled.div` - background: ${palette.gray2}; + background: ${themedPalette.bg_element3}; width: 100%; height: 1px; margin-top: 2rem; @@ -104,14 +105,14 @@ const Separator = styled.div` `; const ProfileIcons = styled.div` - color: ${palette.gray5}; + color: ${themedPalette.text3}; display: flex; svg { cursor: pointer; width: 2rem; height: 2rem; &:hover { - color: ${palette.gray8}; + color: ${themedPalette.text1}; } ${media.small} { width: 1.5rem; diff --git a/src/components/common/__tests__/__snapshots__/PopupOKCancel.test.tsx.snap b/src/components/common/__tests__/__snapshots__/PopupOKCancel.test.tsx.snap index 11520250..71421ac9 100644 --- a/src/components/common/__tests__/__snapshots__/PopupOKCancel.test.tsx.snap +++ b/src/components/common/__tests__/__snapshots__/PopupOKCancel.test.tsx.snap @@ -3,16 +3,16 @@ exports[`PopupOKCancel matches snapshot 1`] = `

제목 @@ -26,7 +26,7 @@ exports[`PopupOKCancel matches snapshot 1`] = ` class="button-area" > )} diff --git a/src/components/post/PostHead.tsx b/src/components/post/PostHead.tsx index 7aa8a9c2..3dccd6f8 100644 --- a/src/components/post/PostHead.tsx +++ b/src/components/post/PostHead.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled from 'styled-components'; import VelogResponsive from '../velog/VelogResponsive'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { formatDate } from '../../lib/utils'; import { SeriesPost } from '../../lib/graphql/post'; @@ -29,9 +30,10 @@ const PostHeadBlock = styled(VelogResponsive)` letter-spacing: -0.004em; margin-top: 0; font-weight: 800; - color: ${palette.gray8}; + color: ${themedPalette.text1}; margin-bottom: 2rem; word-break: keep-all; + transition: color 0.125s ease-in; } ${media.medium} { @@ -45,19 +47,19 @@ const PostHeadBlock = styled(VelogResponsive)` const SubInfo = styled.div` align-items: center; font-size: 1rem; - color: ${palette.gray7}; + color: ${themedPalette.text2}; /* font-family: 'Spoqa Han Sans'; */ display: flex; justify-content: space-between; .information { .username { - color: ${palette.gray8}; + color: ${themedPalette.text1}; font-weight: bold; a { color: inherit; text-decoration: none; &:hover { - color: ${palette.gray7}; + color: ${themedPalette.text2}; text-decoration: underline; } } @@ -91,9 +93,9 @@ const EditRemoveGroup = styled.div` background: none; font-size: inherit; cursor: pointer; - color: ${palette.gray6}; + color: ${themedPalette.text3}; &:hover { - color: ${palette.gray9}; + color: ${themedPalette.text1}; } ${media.small} { font-size: 0.875rem; diff --git a/src/components/post/PostLikeShareButtons.tsx b/src/components/post/PostLikeShareButtons.tsx index dd6c93cd..2babe0e5 100644 --- a/src/components/post/PostLikeShareButtons.tsx +++ b/src/components/post/PostLikeShareButtons.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import { usePrevious } from 'react-use'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import { LikeIcon, ShareIcon, ClipIcon } from '../../static/svg'; import { useSpring, animated, config } from 'react-spring'; @@ -23,8 +24,8 @@ const Positioner = styled.div` `; const PostLikeShareButtonsBlock = styled(Sticky)` width: 4rem; - background: ${palette.gray0}; - border: 1px solid ${palette.gray1}; + background: ${themedPalette.bg_element2}; + border: 1px solid ${themedPalette.border4}; border-radius: 2rem; padding: 0.5rem; display: flex; @@ -38,10 +39,10 @@ const CircleButton = styled(animated.div)<{ active?: string }>` display: flex; align-items: center; justify-content: center; - background: white; - border: 1px solid ${palette.gray5}; + background: ${themedPalette.bg_element1}; + border: 1px solid ${themedPalette.border2}; border-radius: 1.5rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; cursor: pointer; z-index: 5; svg { @@ -53,26 +54,26 @@ const CircleButton = styled(animated.div)<{ active?: string }>` } } &:hover { - color: ${palette.gray9}; - border-color: ${palette.gray9}; + color: ${themedPalette.text1}; + border-color: ${themedPalette.text1}; } - ${props => + ${(props) => props.active === 'true' && css` - background: ${palette.teal5}; - border-color: ${palette.teal5}; - color: white; + background: ${themedPalette.primary2}; + border-color: ${themedPalette.primary2}; + color: ${themedPalette.button_text}; &:hover { background: ${palette.teal4}; border-color: ${palette.teal4}; - color: white; + color: ${themedPalette.button_text}; } `} `; const LikeCount = styled.div` margin-top: 0.5rem; - color: ${palette.gray7}; + color: ${themedPalette.text2}; line-height: 1; font-size: 0.75rem; margin-bottom: 1rem; @@ -156,7 +157,7 @@ const PostLikeShareButtons: React.FC = ({ range: [0, 0.25, 0.5, 0.6, 1], output: [1, 1.25, 1, 1.25, 1], }) - .interpolate(x => `scale(${x})`), + .interpolate((x) => `scale(${x})`), }} > @@ -173,7 +174,7 @@ const PostLikeShareButtons: React.FC = ({ output: [0, 1], }) .interpolate( - shareX => + (shareX) => `translate(${shareX * 48}px, -${shareX * 52}px)`, ), }} @@ -190,7 +191,7 @@ const PostLikeShareButtons: React.FC = ({ range: [0, 1], output: [0, 1], }) - .interpolate(shareX => `translate(${shareX * 72}px)`), + .interpolate((shareX) => `translate(${shareX * 72}px)`), }} > onShareClick('twitter')}> @@ -206,7 +207,8 @@ const PostLikeShareButtons: React.FC = ({ output: [0, 1], }) .interpolate( - shareX => `translate(${shareX * 48}px, ${shareX * 52}px)`, + (shareX) => + `translate(${shareX * 48}px, ${shareX * 52}px)`, ), }} > diff --git a/src/components/post/PostReplies.tsx b/src/components/post/PostReplies.tsx index aae0e71d..02cd6788 100644 --- a/src/components/post/PostReplies.tsx +++ b/src/components/post/PostReplies.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import { Comment } from '../../lib/graphql/post'; import PostCommentsList from './PostCommentsList'; import useBoolean from '../../lib/hooks/useBoolean'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import PostCommentsWrite from './PostCommentsWrite'; import useInput from '../../lib/hooks/useInput'; @@ -27,7 +28,7 @@ const PullUp = styled.div` const Separator = styled.div` width: 100%; height: 1px; - background: ${palette.gray2}; + background: ${themedPalette.bg_element3}; margin-bottom: 1.5rem; `; @@ -36,19 +37,19 @@ const StartWritingButton = styled.button` height: 2.5rem; font-size: 1rem; border-radius: 4px; - border: 1px solid ${palette.teal6}; + border: 1px solid ${themedPalette.primary1}; display: flex; outline: none; - color: ${palette.teal6}; + color: ${themedPalette.primary1}; width: 100%; align-items: center; justify-content: center; font-weight: 600; - background: white; + background: ${themedPalette.bg_page2}; &:hover, &:focus { - background: ${palette.teal6}; - color: white; + background: ${themedPalette.primary1}; + color: ${themedPalette.button_text}; } `; diff --git a/src/components/post/PostSeriesInfo.tsx b/src/components/post/PostSeriesInfo.tsx index eb6f151d..d3c859d9 100644 --- a/src/components/post/PostSeriesInfo.tsx +++ b/src/components/post/PostSeriesInfo.tsx @@ -21,6 +21,7 @@ import { usePostViewerPrefetch, } from './PostViewerProvider'; import media from '../../lib/styles/media'; +import { themedPalette } from '../../lib/styles/themes'; const PostSeriesInfoBlock = styled.div` margin-top: 2rem; @@ -28,22 +29,25 @@ const PostSeriesInfoBlock = styled.div` ${media.small} { padding: 1rem; } - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; border-radius: 8px; box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.06); position: relative; + svg { + color: ${themedPalette.primary1}; + } h2 { a { text-decoration: none; color: inherit; &:hover { - color: ${palette.gray6}; + color: ${themedPalette.text3}; text-decoration: underline; } } margin-top: 0; /* font-family: 'Spoqa Han Sans'; */ - color: ${palette.gray7}; + color: ${themedPalette.text2}; font-weight: bold; padding-right: 2rem; font-size: 1.5rem; @@ -70,7 +74,7 @@ const Right = styled.div` align-items: center; .series-number { font-size: 0.875rem; - color: ${palette.gray5}; + color: ${themedPalette.text3}; } `; @@ -78,18 +82,18 @@ const Fold = styled.div` display: flex; align-items: center; margin-left: -5px; - color: ${palette.gray7}; + color: ${themedPalette.text2}; line-height: 1; cursor: pointer; svg { margin-right: 0.25rem; - color: ${palette.gray8}; + color: ${themedPalette.text1}; font-size: 1.5rem; } &:hover { - color: ${palette.gray9}; + color: ${themedPalette.text1}; svg { - color: ${palette.gray9}; + color: ${themedPalette.text1}; } } `; @@ -115,13 +119,13 @@ const NavigateButton = styled.button` align-items: center; justify-content: center; font-size: 1.25rem; - color: ${palette.teal6}; - background: white; - border: 1px solid ${palette.gray1}; + color: ${themedPalette.primary1}; + background: ${themedPalette.bg_element1}; + border: 1px solid ${themedPalette.border4}; padding: 0; cursor: pointer; &:hover { - background: ${palette.teal6}; + background: ${themedPalette.primary1}; color: white; } @@ -131,9 +135,10 @@ const NavigateButton = styled.button` &:disabled { cursor: default; - background: ${palette.gray1}; - border: 1px solid ${palette.gray2}; - color: ${palette.gray4}; + background: ${themedPalette.bg_element2}; + border: 1px solid ${themedPalette.border4}; + color: ${themedPalette.text3}; + opacity: 0.3; } `; @@ -142,7 +147,7 @@ const PostList = styled.ol` line-height: 1.8; font-size: 1rem; /* font-family: 'Spoqa Han Sans'; */ - color: ${palette.gray7}; + color: ${themedPalette.text2}; counter-reset: item; ${media.small} { font-size: 0.875rem; @@ -154,7 +159,7 @@ const PostList = styled.ol` li:before { content: counter(item) '. '; counter-increment: item; - color: ${palette.gray5}; + color: ${themedPalette.text3}; font-style: italic; margin-right: 0.25rem; } @@ -162,7 +167,7 @@ const PostList = styled.ol` color: inherit; text-decoration: none; &:hover { - color: ${palette.gray9}; + color: ${themedPalette.text1}; text-decoration: underline; } } @@ -193,7 +198,7 @@ const PostSeriesInfo: React.FC = ({ urlSlug, }) => { const currentIndex = useMemo( - () => posts.findIndex(post => post.id === postId), + () => posts.findIndex((post) => post.id === postId), [postId, posts], ); const [open, toggle, setValue] = useBoolean(false); @@ -217,13 +222,13 @@ const PostSeriesInfo: React.FC = ({ }, []); const navigatePrev = () => { - const prevPost = posts[posts.findIndex(post => post.id === postId) - 1]; + const prevPost = posts[posts.findIndex((post) => post.id === postId) - 1]; if (!prevPost) return; history.push(`/@${username}/${prevPost.url_slug}`); }; const navigateNext = () => { - const nextPos = posts[posts.findIndex(post => post.id === postId) + 1]; + const nextPos = posts[posts.findIndex((post) => post.id === postId) + 1]; if (!nextPos) return; history.push(`/@${username}/${nextPos.url_slug}`); }; @@ -240,11 +245,14 @@ const PostSeriesInfo: React.FC = ({ {open && ( - {posts.map(post => ( + {posts.map((post) => (
  • {post.title} diff --git a/src/components/post/PostTags.tsx b/src/components/post/PostTags.tsx index 19563b7f..b2fe6570 100644 --- a/src/components/post/PostTags.tsx +++ b/src/components/post/PostTags.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled from 'styled-components'; import { Link } from 'react-router-dom'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const PostTagsBlock = styled.div` @@ -11,7 +12,7 @@ const PostTagsBlock = styled.div` const Tag = styled(Link)` margin-bottom: 0.875rem; - background: ${palette.gray1}; + background: ${themedPalette.bg_element2}; padding-left: 1rem; padding-right: 1rem; height: 2rem; @@ -19,11 +20,11 @@ const Tag = styled(Link)` display: inline-flex; align-items: center; margin-right: 0.875rem; - color: ${palette.teal7}; + color: ${themedPalette.primary1}; text-decoration: none; font-weight: 500; &:hover { - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; } font-size: 0.875rem; `; @@ -35,7 +36,7 @@ export interface PostTagsProps { const PostTags: React.FC = ({ tags }) => { return ( - {tags.map(tag => ( + {tags.map((tag) => ( {tag} diff --git a/src/components/post/PostToc.tsx b/src/components/post/PostToc.tsx index 4539d691..dcedd665 100644 --- a/src/components/post/PostToc.tsx +++ b/src/components/post/PostToc.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState, useCallback } from 'react'; import styled, { css } from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import Sticky from '../common/Sticky'; import { usePostViewerState } from './PostViewerProvider'; @@ -24,12 +25,12 @@ const PostTocBlock = styled(Sticky)` ${media.xlarge} { margin-left: 3rem; } - border-left: 2px solid ${palette.gray2}; + border-left: 2px solid ${themedPalette.border4}; padding-left: 0.75rem; padding-right: 0.75rem; padding-top: 0.25rem; padding-bottom: 0.25rem; - color: ${palette.gray6}; + color: ${themedPalette.text3}; line-height: 1.5; font-size: 0.875rem; max-height: calc(100vh - 128px); @@ -42,7 +43,7 @@ const PostTocBlock = styled(Sticky)` &:hover { width: 16px; } - background: ${palette.gray1}; + background: ${themedPalette.bg_element2}; } &::-webkit-scrollbar-thumb { @@ -57,15 +58,15 @@ const TocItem = styled.div<{ active: boolean }>` transition: 0.125s all ease-in; a { &:hover { - color: ${palette.gray9}; + color: ${themedPalette.text1}; } text-decoration: none; color: inherit; } - ${props => + ${(props) => props.active && css` - color: ${palette.gray9}; + color: ${themedPalette.text1}; transform: scale(1.05); `} & + & { @@ -109,7 +110,7 @@ const PostToc: React.FC = () => { useEffect(() => { updateTocPositions(); let prevScrollHeight = document.body.scrollHeight; - let timeoutId: number | null = null; + let timeoutId: ReturnType | null = null; function checkScrollHeight() { const scrollHeight = document.body.scrollHeight; if (prevScrollHeight !== scrollHeight) { @@ -129,7 +130,7 @@ const PostToc: React.FC = () => { const onScroll = useCallback(() => { const scrollTop = getScrollTop(); if (!headingTops) return; - const currentHeading = [...headingTops].reverse().find(headingTop => { + const currentHeading = [...headingTops].reverse().find((headingTop) => { return scrollTop >= headingTop.top - 4; }); if (!currentHeading) { @@ -158,7 +159,7 @@ const PostToc: React.FC = () => { - {toc.map(item => ( + {toc.map((item) => ( { it('shows inactive button', () => { const utils = setup({ liked: false }); const button = utils.getByTestId('like-btn'); - expect(button).toHaveStyle('background: white'); + expect(button).toHaveStyle('background: ${themedPalette.bg_element1}'); }); it('shows active button', () => { const utils = setup({ liked: true }); const button = utils.getByTestId('like-btn'); - expect(button).toHaveStyle(`background: ${palette.teal5}`); + expect(button).toHaveStyle(`background: ${themedPalette.primary2}`); }); }); diff --git a/src/components/postStats/PostStats.tsx b/src/components/postStats/PostStats.tsx index 13f07342..fc24ee40 100644 --- a/src/components/postStats/PostStats.tsx +++ b/src/components/postStats/PostStats.tsx @@ -4,6 +4,7 @@ import SpinnerBlock from '../common/SpinnerBlock'; import { useQuery } from '@apollo/react-hooks'; import { GET_STATS, Stats } from '../../lib/graphql/post'; import { useParams } from 'react-router-dom'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import format from 'date-fns/format'; import { loadScript } from '../../lib/utils'; @@ -171,7 +172,7 @@ const LoaderWrapper = styled.div` const Block = styled.div``; const Info = styled.div` - background: ${palette.gray0}; + background: ${themedPalette.bg_element2}; padding: 1.5rem; border-radius: 0.5rem; `; @@ -180,11 +181,11 @@ const Row = styled.div` line-height: 1.5; .name { - color: ${palette.gray9}; + color: ${themedPalette.text1}; font-weight: bold; } .value { - color: ${palette.gray7}; + color: ${themedPalette.text2}; margin-left: 1rem; } diff --git a/src/components/register/RegisterForm.tsx b/src/components/register/RegisterForm.tsx index 4e225c00..36f02b51 100644 --- a/src/components/register/RegisterForm.tsx +++ b/src/components/register/RegisterForm.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import LabelInput from '../common/LabelInput'; import useInputs from '../../lib/hooks/useInputs'; import RoundButton from '../common/RoundButton'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; const RegisterFormBlock = styled.div` diff --git a/src/components/register/RegisterTemplate.tsx b/src/components/register/RegisterTemplate.tsx index ac9675e0..9233e69e 100644 --- a/src/components/register/RegisterTemplate.tsx +++ b/src/components/register/RegisterTemplate.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import styled from 'styled-components'; +import { themedPalette } from '../../lib/styles/themes'; import palette from '../../lib/styles/palette'; import media from '../../lib/styles/media'; @@ -10,13 +11,13 @@ const RegisterTemplateBlock = styled.div` line-height: 1.5; h1 { font-size: 4rem; - color: ${palette.gray9}; + color: ${themedPalette.text1}; font-weight: bolder; margin: 0; } .description { font-size: 1.5rem; - color: ${palette.gray9}; + color: ${themedPalette.text1}; } ${media.small} { diff --git a/src/components/register/__tests__/__snapshots__/RegisterForm.test.tsx.snap b/src/components/register/__tests__/__snapshots__/RegisterForm.test.tsx.snap index 5d91cac3..34ffdc86 100644 --- a/src/components/register/__tests__/__snapshots__/RegisterForm.test.tsx.snap +++ b/src/components/register/__tests__/__snapshots__/RegisterForm.test.tsx.snap @@ -3,10 +3,10 @@ exports[`RegisterForm matches snapshot 1`] = `