diff --git a/config/config.json b/config/config.json index ad5549cdf..a39914e0d 100755 --- a/config/config.json +++ b/config/config.json @@ -1,6 +1,6 @@ { "//--- general configs ---//": "", - "DEFAULT_THEME": "github", + "DEFAULT_THEME": "day", "SENIOR_AMOUNT_THRESHOLD": 51.2, "SPONSOR_AMOUNT_THRESHOLD": 3999, "PAGE_SIZE": { diff --git a/src/containers/content/LandingPage/styles/feature_wall/card.ts b/src/containers/content/LandingPage/styles/feature_wall/card.ts index 4216cbeed..91f6497c5 100644 --- a/src/containers/content/LandingPage/styles/feature_wall/card.ts +++ b/src/containers/content/LandingPage/styles/feature_wall/card.ts @@ -1,8 +1,7 @@ import styled from 'styled-components' import type { TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorBgTheme } from '@/css' import Img from '@/Img' @@ -29,8 +28,8 @@ export const Avatar = styled(Img)<{ color: TColorName }>` border: 2px solid; padding: 2px; border-color: gold; - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + border-color: ${({ color }) => baseColorBgTheme(color)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; ` export const User = styled.div`` diff --git a/src/containers/content/LandingPage/styles/feature_wall/user_voice.ts b/src/containers/content/LandingPage/styles/feature_wall/user_voice.ts index 7a036bcd3..d60d3a0c3 100644 --- a/src/containers/content/LandingPage/styles/feature_wall/user_voice.ts +++ b/src/containers/content/LandingPage/styles/feature_wall/user_voice.ts @@ -1,10 +1,7 @@ import styled from 'styled-components' import type { TTestable, TColorName } from '@/spec' - -import css, { theme } from '@/css' -import { camelize } from '@/fmt' - +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' import TreesSVG from '@/icons/Trees' export const Wrapper = styled.div.attrs(({ testid }) => ({ @@ -47,7 +44,7 @@ export const TreeWrapper = styled.div` export const TreesIcon = styled(TreesSVG)` height: 240px; width: 700px; - fill: ${theme('artivle.digest')}; + fill: ${theme('article.digest')}; ${css.media.mobile` width: 100%; @@ -75,12 +72,9 @@ export const Avatar = styled.div<{ color: TColorName }>` ${css.circle(30)}; ${css.row('align-both')}; padding: 2px; - color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + color: ${({ color }) => baseColorTheme(color)}; font-size: 12px; - - /* border: 2px solid; */ - /* border-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; */ - background-color: ${({ color }) => theme(`baseColor.${color.toLowerCase()}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; ${css.media.mobile` ${css.circle(20)}; diff --git a/src/containers/content/LandingPage/styles/users_wall/card.ts b/src/containers/content/LandingPage/styles/users_wall/card.ts index 332473411..c5ba10fff 100644 --- a/src/containers/content/LandingPage/styles/users_wall/card.ts +++ b/src/containers/content/LandingPage/styles/users_wall/card.ts @@ -2,9 +2,7 @@ import styled from 'styled-components' import type { TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' - +import css, { theme, baseColorBgTheme } from '@/css' import Img from '@/Img' export const Wrapper = styled.div` @@ -35,8 +33,8 @@ export const Avatar = styled(Img)<{ color: TColorName }>` ${css.circle(30)}; border: 2px solid; padding: 2px; - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; - background-color: ${({ color }) => theme(`baseColor.${color.toLowerCase()}Bg`)}; + border-color: ${({ color }) => baseColorBgTheme(color)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; ${css.media.mobile` ${css.circle(25)}; diff --git a/src/containers/content/LandingPage/styles/users_wall/index.ts b/src/containers/content/LandingPage/styles/users_wall/index.ts index 0ce0d0aac..6f0d80872 100644 --- a/src/containers/content/LandingPage/styles/users_wall/index.ts +++ b/src/containers/content/LandingPage/styles/users_wall/index.ts @@ -2,7 +2,7 @@ import styled from 'styled-components' import type { TColorName, TTestable } from '@/spec' -import css, { theme } from '@/css' +import css, { theme, baseColorBgTheme } from '@/css' export const Wrapper = styled.div.attrs(({ testid }) => ({ 'data-test-id': testid, @@ -91,5 +91,5 @@ export const Hightlight = styled.span<{ color: TColorName }>` color: ${theme('article.title')}; font-weight: 500; padding: 0 2px; - background-color: ${({ color }) => theme(`baseColor.${color.toLowerCase()}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; ` diff --git a/src/containers/content/UserContent/styles/index.ts b/src/containers/content/UserContent/styles/index.ts index a7ce9cf4f..67a5142e9 100755 --- a/src/containers/content/UserContent/styles/index.ts +++ b/src/containers/content/UserContent/styles/index.ts @@ -40,7 +40,7 @@ export const ContentWrapper = styled.div<{ hasContentBg: boolean }>` padding: 20px; padding-top: 15px; - background: ${({ hasContentBg }) => (hasContentBg ? theme('thread.bg') : 'transparent')}; + background: ${({ hasContentBg }) => (hasContentBg ? theme('hoverBg') : 'transparent')}; ${css.media.mobile` padding: 0; diff --git a/src/containers/editor/CommunityEditor/styles/banner/finished.ts b/src/containers/editor/CommunityEditor/styles/banner/finished.ts index 8d775561e..f778b2bc5 100755 --- a/src/containers/editor/CommunityEditor/styles/banner/finished.ts +++ b/src/containers/editor/CommunityEditor/styles/banner/finished.ts @@ -9,8 +9,6 @@ export const Wrapper = styled.div` position: relative; ${css.column('align-both')}; color: ${theme('article.digest')}; - /* background-image: linear-gradient(#043B49, #022A35); */ - background-image: ${theme('banner.linearGradient')}; padding-top: 5%; padding-bottom: 5%; width: 100%; diff --git a/src/containers/editor/CommunityEditor/styles/banner/setup_domain.ts b/src/containers/editor/CommunityEditor/styles/banner/setup_domain.ts index fb20f4354..474acd18d 100755 --- a/src/containers/editor/CommunityEditor/styles/banner/setup_domain.ts +++ b/src/containers/editor/CommunityEditor/styles/banner/setup_domain.ts @@ -8,8 +8,6 @@ export const Wrapper = styled.div` position: relative; ${css.column('align-both')}; color: ${theme('article.digest')}; - /* background-image: linear-gradient(#043B49, #022A35); */ - background-image: ${theme('banner.linearGradient')}; width: 100%; height: 260px; ` diff --git a/src/containers/editor/CommunityEditor/styles/banner/setup_extra.ts b/src/containers/editor/CommunityEditor/styles/banner/setup_extra.ts index 77cbb8f69..8b17d2529 100644 --- a/src/containers/editor/CommunityEditor/styles/banner/setup_extra.ts +++ b/src/containers/editor/CommunityEditor/styles/banner/setup_extra.ts @@ -11,7 +11,6 @@ export const Wrapper = styled.div` position: relative; ${css.column('align-both')}; color: ${theme('article.digest')}; - background-image: ${theme('banner.linearGradient')}; width: 100%; padding-top: 3%; ` diff --git a/src/containers/editor/CommunityEditor/styles/banner/setup_info.ts b/src/containers/editor/CommunityEditor/styles/banner/setup_info.ts index a6797221f..c146c2f02 100755 --- a/src/containers/editor/CommunityEditor/styles/banner/setup_info.ts +++ b/src/containers/editor/CommunityEditor/styles/banner/setup_info.ts @@ -12,7 +12,6 @@ export const Wrapper = styled.div` position: relative; ${css.column('align-both')}; color: ${theme('article.digest')}; - background-image: ${theme('banner.linearGradient')}; width: 100%; height: 300px; ` diff --git a/src/containers/editor/CommunityEditor/styles/content/fake_browser/index.ts b/src/containers/editor/CommunityEditor/styles/content/fake_browser/index.ts index 6e7dbd1e7..f1046e729 100755 --- a/src/containers/editor/CommunityEditor/styles/content/fake_browser/index.ts +++ b/src/containers/editor/CommunityEditor/styles/content/fake_browser/index.ts @@ -12,7 +12,7 @@ export const Wrapper = styled.div` width: 100%; min-height: 500px; border-radius: 12px; - background: ${theme('alplaBg')}; + background: ${theme('alphaBg')}; border: 1px solid; border-color: #e5e5e5; /* border-color: ${theme('hoverBg')}; */ @@ -29,7 +29,7 @@ export const Header = styled.div` border-top-left-radius: 5px; border-top-right-radius: 5px; height: 36px; - background: ${theme('alplaBg')}; + background: ${theme('alphaBg')}; ` export const Tab = styled.div` ${css.row('align-center')}; diff --git a/src/containers/layout/GlobalLayout/Wallpaper.tsx b/src/containers/layout/GlobalLayout/Wallpaper.tsx index e0a56974d..c3f37be3a 100755 --- a/src/containers/layout/GlobalLayout/Wallpaper.tsx +++ b/src/containers/layout/GlobalLayout/Wallpaper.tsx @@ -2,20 +2,22 @@ import { FC } from 'react' import { observer } from 'mobx-react' import useWallpaper from '@/hooks/useWallpaper' +import useTheme from '@/hooks/useTheme' + import { parseWallpaper } from '@/wallpaper' import { Wrapper } from './styles/wallpaper' const Wallpaper: FC = () => { - const theWallpaper = useWallpaper() + const { wallpapers, wallpaper, customWallpaper } = useWallpaper() + const { curTheme } = useTheme() - const { wallpapers, wallpaper, customWallpaper } = theWallpaper const { background, effect } = parseWallpaper(wallpapers, wallpaper, customWallpaper) // for custom image/svg // for use style object not passing props // @link see https://github.com/styled-components/styled-components/issues/3315#issuecomment-885977691 - return + return } export default observer(Wallpaper) diff --git a/src/containers/layout/GlobalLayout/index.tsx b/src/containers/layout/GlobalLayout/index.tsx index 6052481e8..8455f1391 100755 --- a/src/containers/layout/GlobalLayout/index.tsx +++ b/src/containers/layout/GlobalLayout/index.tsx @@ -91,7 +91,6 @@ const GlobalLayoutContainer: FC = ({ globalLayout: store, children }) => - {/* TODO: extract */} ` +type TWrapper = { effect: string; themeName: TThemeName } +export const Wrapper = styled.div` position: fixed; top: 0; height: 100%; @@ -9,6 +13,7 @@ export const Wrapper = styled.div<{ effect: string }>` ${({ effect }) => effect || ''}; + filter: ${({ themeName }) => (themeName === THEME.NIGHT ? 'brightness(0.85)' : '')}; /* adjust s value for speed */ /* position: fixed; */ /* see https://www.zhangxinxu.com/wordpress/2015/11/css3-will-change-improve-paint/ */ diff --git a/src/containers/layout/ThemePalette/index.tsx b/src/containers/layout/ThemePalette/index.tsx index 5361696a2..6d44ffbc9 100755 --- a/src/containers/layout/ThemePalette/index.tsx +++ b/src/containers/layout/ThemePalette/index.tsx @@ -3,14 +3,13 @@ * because mobx's observer mechanism, we should manually watch the theme * otherwhise the render will not be triggled */ - import { FC, Fragment, ReactNode } from 'react' +import { observer } from 'mobx-react' import Head from 'next/head' import { ThemeProvider } from 'styled-components' -import type { TThemeMap } from '@/spec' import usePrimaryColor from '@/hooks/usePrimaryColor' -import { bond } from '@/mobx' +import useThemeData from '@/hooks/useThemeData' import ThirdPartyOverWrite from './ThirdPartyOverWrite' import ScrollBarStyle from './ScrollBarStyle' @@ -19,15 +18,14 @@ import { CodeSyxHighlight } from './dynamic' type TProps = { children: ReactNode - theme?: { - themeData: TThemeMap - } } -const ThemeContainer: FC = ({ children, theme: { themeData } }) => { +const ThemePalette: FC = ({ children }) => { + const themeData = useThemeData() const primaryColor = usePrimaryColor() // see https://css-tricks.com/meta-theme-color-and-trickery/ // theme seems conflict with manifest + return ( @@ -47,7 +45,7 @@ const ThemeContainer: FC = ({ children, theme: { themeData } }) => { ) } -export default bond(ThemeContainer, 'theme') as FC +export default observer(ThemePalette) // about meta theme-color // see: https://stackoverflow.com/questions/26960703/how-to-change-the-color-of-header-bar-and-address-bar-in-newest-chrome-version-o diff --git a/src/containers/thread/DashboardThread/store/Models.ts b/src/containers/thread/DashboardThread/store/Models.ts index 60c78409a..8dce6391e 100644 --- a/src/containers/thread/DashboardThread/store/Models.ts +++ b/src/containers/thread/DashboardThread/store/Models.ts @@ -147,7 +147,7 @@ export const settingsModalFields = { docFaqLayout: T.opt(T.enum(values(DOC_FAQ_LAYOUT)), DOC_FAQ_LAYOUT.COLLAPSE), avatarLayout: T.opt(T.enum(values(AVATAR_LAYOUT)), AVATAR_LAYOUT.SQUARE), brandLayout: T.opt(T.enum(values(BRAND_LAYOUT)), BRAND_LAYOUT.BOTH), - bannerLayout: T.opt(T.enum(values(BANNER_LAYOUT)), BANNER_LAYOUT.SIDEBAR), + bannerLayout: T.opt(T.enum(values(BANNER_LAYOUT)), BANNER_LAYOUT.HEADER), topbarLayout: T.opt(T.enum(values(TOPBAR_LAYOUT)), TOPBAR_LAYOUT.NO), topbarBg: T.opt(T.enum(keys(COLORS)), COLOR_NAME.ORANGE), diff --git a/src/containers/thread/DashboardThread/styles/header/editors/group_head.ts b/src/containers/thread/DashboardThread/styles/header/editors/group_head.ts index 3cd4ac704..269fc7177 100644 --- a/src/containers/thread/DashboardThread/styles/header/editors/group_head.ts +++ b/src/containers/thread/DashboardThread/styles/header/editors/group_head.ts @@ -18,7 +18,7 @@ export const Title = styled.div` font-size: 14px; ` export const HintTitle = styled(Title)` - color: ${theme('article.ditest')}; + color: ${theme('article.digest')}; margin-top: 4px; font-size: 12px; font-style: italic; diff --git a/src/containers/thread/DashboardThread/styles/layout/avatar_layout.ts b/src/containers/thread/DashboardThread/styles/layout/avatar_layout.ts index 7c07c8e03..a85a64064 100644 --- a/src/containers/thread/DashboardThread/styles/layout/avatar_layout.ts +++ b/src/containers/thread/DashboardThread/styles/layout/avatar_layout.ts @@ -1,9 +1,8 @@ import styled from 'styled-components' import type { TActive } from '@/spec' -import css, { theme } from '@/css' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' -import { camelize } from '@/fmt' import { LineDivider } from '@/widgets/Common' import { BaseSection, BlockBase } from '.' @@ -23,12 +22,12 @@ export const Avatar = styled.div` font-size: 13px; font-weight: bold; border-radius: ${({ circle }) => (circle ? '100px' : '6px')}; - color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + color: ${({ color }) => baseColorTheme(color)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; margin-left: ${({ left }) => left}; margin-left: 5px; border: 1px solid; - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + border-color: ${({ color }) => baseColorTheme(color)}; ` export const AvatarList = styled.div` ${css.row('align-center')}; diff --git a/src/containers/thread/DashboardThread/styles/layout/doc_layout/main_template.ts b/src/containers/thread/DashboardThread/styles/layout/doc_layout/main_template.ts index 4d0ecf2a9..095bb779b 100644 --- a/src/containers/thread/DashboardThread/styles/layout/doc_layout/main_template.ts +++ b/src/containers/thread/DashboardThread/styles/layout/doc_layout/main_template.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' import ToolSVG from '@/icons/Heart' @@ -53,13 +52,13 @@ export const IconWrapper = styled.div<{ color: TColorName }>` ${css.size(15)}; ${css.row('align-both')}; border-radius: 2px; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; margin-bottom: 8px; margin-right: 20px; ` export const ToolIcon = styled(ToolSVG)<{ color: TColorName }>` ${css.size(8)}; - fill: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + fill: ${({ color }) => baseColorTheme(color)}; ` export const ListContent = styled.div` diff --git a/src/containers/thread/DashboardThread/styles/layout/kanban_layout/board_layout.ts b/src/containers/thread/DashboardThread/styles/layout/kanban_layout/board_layout.ts index 330eb44e5..bc125a699 100644 --- a/src/containers/thread/DashboardThread/styles/layout/kanban_layout/board_layout.ts +++ b/src/containers/thread/DashboardThread/styles/layout/kanban_layout/board_layout.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TActive, TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' import DiceSVG from '@/icons/Dice' import ResetSVG from '@/icons/Reset' @@ -45,7 +44,7 @@ export const Board = styled.div` width: 33.3%; height: 280px; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; border-radius: 8px; border-bottom-left-radius: 0; @@ -113,16 +112,16 @@ export const Preset = styled.div<{ setable?: boolean }>` type TColorBall = { color: TColorName; setable?: boolean } export const ColorBall = styled.div` - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; border: 1px dashed; - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + border-color: ${({ color }) => baseColorTheme(color)}; ${css.circle(16)}; padding: 5px; &:hover { border: ${({ setable }) => (setable ? '1px solid' : '1px dashed')}; - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + border-color: ${({ color }) => baseColorTheme(color)}; } transition: all 0.2s; diff --git a/src/containers/thread/DocThread/styles/article_layout/pined_tree.ts b/src/containers/thread/DocThread/styles/article_layout/pined_tree.ts index bcdd96779..b88b7317f 100644 --- a/src/containers/thread/DocThread/styles/article_layout/pined_tree.ts +++ b/src/containers/thread/DocThread/styles/article_layout/pined_tree.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme } from '@/css' import GithubSVG from '@/icons/social/Github' import QuestionSVG from '@/icons/Question' @@ -31,7 +30,7 @@ export const Cover = styled.div<{ color?: TColorName }>` left: 0; top: 0; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + background-color: ${({ color }) => baseColorTheme(color)}; border-radius: 5px; opacity: 0.6; @@ -68,7 +67,7 @@ export const Title = styled.div<{ color: TColorName }>` color: ${theme('article.digest')}; &:hover { - color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + color: ${({ color }) => baseColorTheme(color)}; font-weight: 500; } diff --git a/src/containers/thread/DocThread/styles/blocks_layout/category.ts b/src/containers/thread/DocThread/styles/blocks_layout/category.ts index 822aadc6d..f52491349 100644 --- a/src/containers/thread/DocThread/styles/blocks_layout/category.ts +++ b/src/containers/thread/DocThread/styles/blocks_layout/category.ts @@ -1,8 +1,7 @@ import styled from 'styled-components' import type { TColorName, TTestable } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorBgTheme } from '@/css' type TWrapper = TTestable & { color?: string } export const Wrapper = styled.div.attrs(({ testid }) => ({ @@ -35,7 +34,7 @@ export const IconWrapper = styled.div<{ color: TColorName }>` border-radius: 12px; margin-left: -1px; ${css.row('align-both')}; - background: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background: ${({ color }) => baseColorBgTheme(color)}; margin-bottom: 8px; filter: saturate(0.7); diff --git a/src/containers/thread/DocThread/styles/lists_layout/category.ts b/src/containers/thread/DocThread/styles/lists_layout/category.ts index c728c89ae..ef0eeaa82 100644 --- a/src/containers/thread/DocThread/styles/lists_layout/category.ts +++ b/src/containers/thread/DocThread/styles/lists_layout/category.ts @@ -1,8 +1,7 @@ import styled from 'styled-components' import type { TColorName, TTestable } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorBgTheme } from '@/css' import ArrowButton from '@/widgets/Buttons/ArrowButton' @@ -37,7 +36,7 @@ export const IconWrapper = styled.div<{ color: TColorName }>` ${css.row('align-both')}; margin-top: -35px; border-radius: 12px; - background: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background: ${({ color }) => baseColorBgTheme(color)}; opacity: 0.8; ` export const Title = styled.div` diff --git a/src/containers/thread/KanbanThread/styles/columns.ts b/src/containers/thread/KanbanThread/styles/columns.ts index 117dc629e..42eb9c940 100644 --- a/src/containers/thread/KanbanThread/styles/columns.ts +++ b/src/containers/thread/KanbanThread/styles/columns.ts @@ -1,8 +1,7 @@ import styled from 'styled-components' import type { TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorBgTheme } from '@/css' import GtdWipSVG from '@/icons/GtdWip' import GtdDoneSVG from '@/icons/GtdDone' @@ -23,7 +22,7 @@ export const Header = styled.div` padding-left: 3px; ` export const Body = styled.div<{ color: TColorName }>` - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; padding: 8px; padding-bottom: 0; border-radius: 12px; diff --git a/src/containers/tool/AbuseReport/styles/report_content/main.ts b/src/containers/tool/AbuseReport/styles/report_content/main.ts index af112ae2f..ed745c0e3 100755 --- a/src/containers/tool/AbuseReport/styles/report_content/main.ts +++ b/src/containers/tool/AbuseReport/styles/report_content/main.ts @@ -23,7 +23,6 @@ export const FooterPanel = styled.div` padding-left: 35px; width: 100%; background: ${theme('modal.subPanel')}; - /* background: ${theme('modal.panelBg')}; */ height: 56px; color: ${theme('article.digest')}; font-size: 13px; diff --git a/src/containers/tool/Cashier/styles/payment_sidebar.ts b/src/containers/tool/Cashier/styles/payment_sidebar.ts index 3418cca3f..05dad787b 100755 --- a/src/containers/tool/Cashier/styles/payment_sidebar.ts +++ b/src/containers/tool/Cashier/styles/payment_sidebar.ts @@ -65,7 +65,7 @@ export const QuestionWrapper = styled.div` ${css.row('align-center')}; color: ${theme('article.digest')}; &:hover { - color: ${theme('thread.articeTitle')}; + color: ${theme('article.title')}; cursor: pointer; } ` diff --git a/src/containers/tool/Drawer/Viewer/MobileView.tsx b/src/containers/tool/Drawer/Viewer/MobileView.tsx index 4c91fe3e6..37eb54540 100755 --- a/src/containers/tool/Drawer/Viewer/MobileView.tsx +++ b/src/containers/tool/Drawer/Viewer/MobileView.tsx @@ -1,8 +1,7 @@ import { FC, ReactNode, useEffect, useState, memo, useRef } from 'react' -import { useTheme } from 'styled-components' -import type { TThemeMap } from '@/spec' import useSwipe from '@/hooks/useSwipe' +import useTheme from '@/hooks/useTheme' import type { TSwipeOption } from '../spec' import Header from '../Header' @@ -34,8 +33,7 @@ const Viewer: FC = ({ disableContentDrag, children, }) => { - // @ts-ignore - const theme: TThemeMap = useTheme() + const { themeMap } = useTheme() // swipe action state for top && bottom // null means restore and close const [swipeDownY, setSwipeDownY] = useState(null) @@ -89,7 +87,7 @@ const Viewer: FC = ({ options={options} mobile > - + ` top: 0; left: 40px; display: block; - background: white; + background: ${theme('bodyBg')}; border-top-left-radius: 8px; border-bottom-left-radius: 28px; box-shadow: ${theme('drawer.closerShadow')}; @@ -34,7 +34,7 @@ export const TopArea = styled.div<{ showShare: boolean }>` &:before { content: ''; position: absolute; - background: white; + background: ${theme('bodyBg')}; bottom: -3px; right: -19px; width: 25px; @@ -42,14 +42,13 @@ export const TopArea = styled.div<{ showShare: boolean }>` transform: rotate(26deg); border-bottom-left-radius: 0; border-bottom-right-radius: 15px; - /* border: 1px solid lightgrey; */ } &:after { // this is for cover the box-shadow content: ''; position: absolute; - background: white; + background: ${theme('bodyBg')}; top: 0; right: -10px; width: 10px; diff --git a/src/containers/unit/Comments/styles/head_bar/publish_bar.ts b/src/containers/unit/Comments/styles/head_bar/publish_bar.ts index 496239def..590d7f5fd 100755 --- a/src/containers/unit/Comments/styles/head_bar/publish_bar.ts +++ b/src/containers/unit/Comments/styles/head_bar/publish_bar.ts @@ -19,7 +19,7 @@ export const Avatar = styled(Img)<{ avatarLayout: TAvatarLayout }>` border-radius: ${({ avatarLayout }) => (avatarLayout === AVATAR_LAYOUT.SQUARE ? '6px' : '100%')}; ` export const UserName = styled.div` - color: ${theme('thread.articleDIgest')}; + color: ${theme('article.digest')}; font-size: 14px; margin-left: 12px; ` diff --git a/src/containers/unit/TagsBar/styles/desktop_view/tag_item.ts b/src/containers/unit/TagsBar/styles/desktop_view/tag_item.ts index 72a4cac9f..a16d8ee65 100755 --- a/src/containers/unit/TagsBar/styles/desktop_view/tag_item.ts +++ b/src/containers/unit/TagsBar/styles/desktop_view/tag_item.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TActive, TPrimaryColor } from '@/spec' -import css, { theme, primaryLightTheme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme, primaryLightTheme } from '@/css' import Img from '@/Img' @@ -42,7 +41,7 @@ export const DotWrapper = styled.div` type THashSign = TActive & { color?: string } export const DotSign = styled.div` ${css.circle(8)}; - background: ${({ color }) => (color ? theme(`baseColor.${camelize(color)}`) : 'none')}; + background: ${({ color }) => (color ? baseColorTheme(color) : 'none')}; opacity: ${({ $active }) => ($active ? 1 : theme('tags.dotOpacity'))}; ${Wrapper}:hover & { diff --git a/src/containers/user/UserProfile/styles/contribute_map.ts b/src/containers/user/UserProfile/styles/contribute_map.ts index aa3963bcc..032a49893 100755 --- a/src/containers/user/UserProfile/styles/contribute_map.ts +++ b/src/containers/user/UserProfile/styles/contribute_map.ts @@ -8,6 +8,7 @@ const dotColor = (scale: string): TTheme => { if (scale === 'empty') { key = 'heatmap.empty' } + // @ts-ignore return theme(key) } diff --git a/src/containers/viewer/ArticleViewer/styles/post_viewer/article_info.ts b/src/containers/viewer/ArticleViewer/styles/post_viewer/article_info.ts index 1a7778965..cd9985ea8 100755 --- a/src/containers/viewer/ArticleViewer/styles/post_viewer/article_info.ts +++ b/src/containers/viewer/ArticleViewer/styles/post_viewer/article_info.ts @@ -8,7 +8,7 @@ export const Wrapper = styled.div` width: 100%; height: 80px; border-bottom: 1px solid; - border-bottom-color: ${theme('drawer.divider')}; + border-bottom-color: ${theme('divider')}; padding-bottom: 12px; margin-top: 8px; ` diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts new file mode 100644 index 000000000..0f2d4a806 --- /dev/null +++ b/src/hooks/useTheme.ts @@ -0,0 +1,30 @@ +import { useContext } from 'react' +import { MobXProviderContext } from 'mobx-react' +import { useTheme as useStyledTheme } from 'styled-components' + +import type { TThemeName, TThemeMap } from '@/spec' + +type TRet = { + curTheme: TThemeName + changeTheme: (name: TThemeName) => void + themeMap: TThemeMap +} +/** + * NOTE: should use observer to wrap the component who use this hook + */ +const useTheme = (): TRet => { + const { store } = useContext(MobXProviderContext) + const styledTheme = useStyledTheme() as TThemeMap + + if (store === null) { + throw new Error('Store cannot be null, please add a context provider') + } + + return { + curTheme: store.theme.curTheme, + changeTheme: (name: TThemeName) => store.theme.changeTheme(name), + themeMap: styledTheme, + } +} + +export default useTheme diff --git a/src/hooks/useThemeData.ts b/src/hooks/useThemeData.ts new file mode 100644 index 000000000..43d1339ba --- /dev/null +++ b/src/hooks/useThemeData.ts @@ -0,0 +1,21 @@ +import { useContext } from 'react' +import { MobXProviderContext } from 'mobx-react' + +import type { TThemeMap } from '@/spec' + +/** + * NOTE: should use observer to wrap the component who use this hook + * this hook is ONLY used for init ThemePalette, cuz the useTheme from + * styled-component can only be used before it init + */ +const useThemeData = (): TThemeMap => { + const { store } = useContext(MobXProviderContext) + + if (store === null) { + throw new Error('Store cannot be null, please add a context provider') + } + + return store.theme.themeData as TThemeMap +} + +export default useThemeData diff --git a/src/spec/enhance.d.ts b/src/spec/enhance.d.ts index f191aba10..e31bf7230 100755 --- a/src/spec/enhance.d.ts +++ b/src/spec/enhance.d.ts @@ -8,3 +8,13 @@ export type { NonNegativeInteger as TNonNegativeInteger, ValueOf as TValueOf, } from 'type-fest' + +// see https://www.raygesualdo.com/posts/flattening-object-keys-with-typescript-types +export type TFlattenObjectKeys< + T extends Record, + Key = keyof T, +> = Key extends string + ? T[Key] extends Record + ? `${Key}.${TFlattenObjectKeys}` + : `${Key}` + : never diff --git a/src/spec/index.ts b/src/spec/index.ts index 10ae68ad6..e731aa14b 100755 --- a/src/spec/index.ts +++ b/src/spec/index.ts @@ -7,7 +7,13 @@ import type { TRootStore as RootStoreType } from '@/stores/RootStore' import type { TArticle } from './article' import type { TCommunity } from './community' -export type { TSnakeUpperCase, TNegativeInteger, TNonNegativeInteger, TValueOf } from './enhance' +export type { + TSnakeUpperCase, + TNegativeInteger, + TNonNegativeInteger, + TValueOf, + TFlattenObjectKeys, +} from './enhance' export type { TMetric } from './metric' export type { diff --git a/src/spec/theme.d.ts b/src/spec/theme.d.ts index d5eaf8f0a..0f3371de6 100755 --- a/src/spec/theme.d.ts +++ b/src/spec/theme.d.ts @@ -1,9 +1,10 @@ -export type TThemeName = 'github' +export type TThemeName = 'day' | 'night' // export type TTheme = ((obj: any) => unknown) | string export type TTheme = any // export type TTheme = string +// TODO: use keyof typeof export type TThemeMap = { name?: string _meta?: { diff --git a/src/stores/ThemeStore/index.ts b/src/stores/ThemeStore/index.ts index 615e94642..7640b0ef9 100755 --- a/src/stores/ThemeStore/index.ts +++ b/src/stores/ThemeStore/index.ts @@ -20,9 +20,6 @@ export const ThemeStore = T.model('ThemeStore', { curTheme: T.opt(T.enum('theme', keys(themeSkins)), DEFAULT_THEME), }) .views((self) => ({ - get root() { - return getParent(self) - }, get themeData() { return themeSkins[self.curTheme] }, diff --git a/src/widgets/AccountUnit/index.tsx b/src/widgets/AccountUnit/index.tsx index 7e3d00ac2..aaf0cbd8f 100644 --- a/src/widgets/AccountUnit/index.tsx +++ b/src/widgets/AccountUnit/index.tsx @@ -6,38 +6,53 @@ import { FC } from 'react' import { observer } from 'mobx-react' +import { includes } from 'ramda' import type { TSpace } from '@/spec' import { buildLog } from '@/logger' import useAccount from '@/hooks/useAccount' import useAvatarLayout from '@/hooks/useAvatarLayout' +import useBannerLayout from '@/hooks/useBannerLayout' +import { BANNER_LAYOUT } from '@/constant/layout' -import { NormalWrapper, WithBgWrapper, Avatar, UnloginIcon, NickName } from './styles' +import { SpaceGrow } from '@/widgets/Common' +import ThemeSwitch from '@/widgets/ThemeSwitch' + +import { NormalWrapper, WithBgWrapper, Avatar, UnloginIcon, NickName, UnLoginText } from './styles' /* eslint-disable-next-line */ const log = buildLog('c:AccountUnit:index') type TProps = { testid?: string - withBg?: boolean withName?: boolean } & TSpace -const AccountUnit: FC = ({ - testid = 'account-unit', - withBg = false, - withName = false, - ...restProps -}) => { +const AccountUnit: FC = ({ testid = 'account-unit', withName = false, ...restProps }) => { const { isLogin, avatar, nickname } = useAccount() const avatarLayout = useAvatarLayout() + const bannerLayout = useBannerLayout() - const Wrapper = withBg ? WithBgWrapper : NormalWrapper + const Wrapper = includes(bannerLayout, [BANNER_LAYOUT.TABBER, BANNER_LAYOUT.SIDEBAR]) + ? WithBgWrapper + : NormalWrapper return ( + {includes(bannerLayout, [BANNER_LAYOUT.HEADER, BANNER_LAYOUT.TABBER]) && ( + + )} + {isLogin ? : } + {!isLogin && withName && 未登入} {isLogin && withName && {nickname}} + + {bannerLayout === BANNER_LAYOUT.SIDEBAR && ( + <> + + + + )} ) } diff --git a/src/widgets/AccountUnit/styles/index.ts b/src/widgets/AccountUnit/styles/index.ts index 05778cb74..52bf7d1a9 100644 --- a/src/widgets/AccountUnit/styles/index.ts +++ b/src/widgets/AccountUnit/styles/index.ts @@ -15,14 +15,14 @@ export const NormalWrapper = styled.div` export const WithBgWrapper = styled(NormalWrapper)` border: 1px solid; border-color: ${theme('divider')}; + height: 32px; border-radius: 10px; padding: 5px 8px; width: auto; background: ${theme('alphaBg')}; - box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + box-shadow: ${theme('popover.boxShadow')}; &:hover { - background: ${theme('alphaBg2')}; cursor: pointer; } ` @@ -33,7 +33,7 @@ export const Avatar = styled(Img)<{ avatarLayout: TAvatarLayout }>` ` export const UnloginIcon = styled(AccountSVG)` fill: ${theme('article.digest')}; - ${css.size(15)}; + ${css.size(13)}; ` export const NickName = styled.div` color: ${theme('article.digest')}; @@ -41,3 +41,8 @@ export const NickName = styled.div` ${css.cutRest('80px')}; margin-left: 10px; ` + +export const UnLoginText = styled(NickName)` + font-size: 12px; + margin-top: 1px; +` diff --git a/src/widgets/AnimatedCount/AnimatedCount.tsx b/src/widgets/AnimatedCount/AnimatedCount.tsx index 027dd41d9..640903f29 100755 --- a/src/widgets/AnimatedCount/AnimatedCount.tsx +++ b/src/widgets/AnimatedCount/AnimatedCount.tsx @@ -1,8 +1,7 @@ import { FC, memo } from 'react' -import { useTheme } from 'styled-components' -import type { TThemeMap } from '@/spec' import SIZE from '@/constant/size' +import useTheme from '@/hooks/useTheme' import FlipNumbers from 'react-flip-numbers' @@ -18,14 +17,14 @@ const AnimatedCount: FC = ({ }) => { const numSize = getFontSize(size) const offset = getFlipNumOffset(size) - const theme = useTheme() as TThemeMap + const { themeMap } = useTheme() return ( (({ testid }) => ({ @@ -19,7 +17,7 @@ export const Wrapper = styled.div.attrs(({ testid }) => ({ height: 120px; /* background: #fafafb; */ - background-color: ${({ color }) => theme(`baseColor.${color.toLowerCase()}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; border-radius: 15px; ${(props) => css.spaceMargins(props)}; @@ -70,7 +68,7 @@ export const Title = styled.span<{ color: TColorName }>` position: absolute; left: 0; bottom: 1px; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; opacity: 0.25; } ` @@ -101,6 +99,6 @@ export const NotifyIcon = styled(BroadcastSVG)<{ color: TColorName }>` margin-right: 5px; transform: rotateZ(20deg) rotateY(180deg); mix-blend-mode: color-burn; - fill: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + fill: ${({ color }) => baseColorTheme(color)}; opacity: 0.3; ` diff --git a/src/widgets/ArticleReadLabel/ReadLabel.tsx b/src/widgets/ArticleReadLabel/ReadLabel.tsx index c4fd10fce..c01a88bce 100755 --- a/src/widgets/ArticleReadLabel/ReadLabel.tsx +++ b/src/widgets/ArticleReadLabel/ReadLabel.tsx @@ -1,4 +1,5 @@ -import { FC, memo } from 'react' +import { FC } from 'react' +import { observer } from 'mobx-react' import useAccount from '@/hooks/useAccount' import { ReadedLabel } from './styles' @@ -6,9 +7,8 @@ import type { TProps } from '.' const ReadLabel: FC = ({ article, top, left }) => { const accountInfo = useAccount() - const isLogin = !!accountInfo - if (!isLogin) return null + if (!accountInfo.isLogin) return null const { markViewed } = accountInfo.customization const { viewerHasViewed } = article @@ -20,4 +20,4 @@ const ReadLabel: FC = ({ article, top, left }) => { return null } -export default memo(ReadLabel) +export default observer(ReadLabel) diff --git a/src/widgets/ArticleReadLabel/index.tsx b/src/widgets/ArticleReadLabel/index.tsx index 4d3a47296..6f14c1079 100755 --- a/src/widgets/ArticleReadLabel/index.tsx +++ b/src/widgets/ArticleReadLabel/index.tsx @@ -2,10 +2,10 @@ * ArticleReadLabel */ -import { FC, memo } from 'react' +import { FC } from 'react' +import { observer } from 'mobx-react' import { buildLog } from '@/logger' -import { nilOrEmpty } from '@/validator' import useAccount from '@/hooks/useAccount' import { ReadedLabel } from './styles' @@ -25,7 +25,7 @@ const ArticleReadLabel: FC = ({ article, top = 24, left = -30 }) => { const accountInfo = useAccount() const { isPinned, viewerHasViewed } = article - if (nilOrEmpty(accountInfo) || isPinned) return null + if (!accountInfo.isLogin || isPinned) return null const { markViewed } = accountInfo.customization @@ -37,4 +37,4 @@ const ArticleReadLabel: FC = ({ article, top = 24, left = -30 }) => { return null } -export default memo(ArticleReadLabel) +export default observer(ArticleReadLabel) diff --git a/src/widgets/BuyMeChuanChuan/styles/unlogin_note.ts b/src/widgets/BuyMeChuanChuan/styles/unlogin_note.ts index 85b937dc0..d92f70fae 100755 --- a/src/widgets/BuyMeChuanChuan/styles/unlogin_note.ts +++ b/src/widgets/BuyMeChuanChuan/styles/unlogin_note.ts @@ -16,7 +16,7 @@ export const LoginLabel = styled.div` &:hover { cursor: pointer; - color: ${theme('thread.title')}; + color: ${theme('article.title')}; text-decoration: underline; } ` diff --git a/src/widgets/ChangelogItem/styles/outline_layout/index.ts b/src/widgets/ChangelogItem/styles/outline_layout/index.ts index cb17fb56f..764eb2b75 100755 --- a/src/widgets/ChangelogItem/styles/outline_layout/index.ts +++ b/src/widgets/ChangelogItem/styles/outline_layout/index.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TTestable } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorBgTheme } from '@/css' import CommentSVG from '@/icons/Comment' @@ -84,6 +83,6 @@ export const TagsWrapper = styled.div` ` export const TagDot = styled.div<{ color: string }>` ${css.circle(6)}; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background-color: ${({ color }) => baseColorBgTheme(color)}; margin-left: 6px; ` diff --git a/src/widgets/ChangelogItem/styles/solid_tag_list.ts b/src/widgets/ChangelogItem/styles/solid_tag_list.ts index 001407d14..3f5ea19ce 100644 --- a/src/widgets/ChangelogItem/styles/solid_tag_list.ts +++ b/src/widgets/ChangelogItem/styles/solid_tag_list.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TColorName } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorBgTheme } from '@/css' export const Wrapper = styled.div` ${css.row('align-center')}; @@ -16,7 +15,7 @@ export const Wrapper = styled.div` ` export const TagWrapper = styled.div<{ color: TColorName }>` - background: ${({ color }) => theme(`baseColor.${color.toLowerCase()}Bg`)}; + background: ${({ color }) => baseColorBgTheme(color)}; padding: 2px 10px; border-radius: 10px; @@ -26,7 +25,6 @@ export const TagWrapper = styled.div<{ color: TColorName }>` ` export const Name = styled.div` - /* color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; */ color: ${theme('article.digest')}; font-size: 11px; font-weight: 400; diff --git a/src/widgets/ColorSelector/styles/index.ts b/src/widgets/ColorSelector/styles/index.ts index b5fd2e79f..d703e6dd6 100755 --- a/src/widgets/ColorSelector/styles/index.ts +++ b/src/widgets/ColorSelector/styles/index.ts @@ -2,10 +2,8 @@ import styled from 'styled-components' import type { TTestable, TActive, TColorName } from '@/spec' -// import Img from '@/Img' import HookSVG from '@/icons/Hook' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' export const Wrapper = styled.div.attrs(({ testid }) => ({ 'data-test-id': testid, @@ -21,13 +19,12 @@ type TDot = TActive & { color: string; colorName: TColorName; bgMode: boolean } export const Dot = styled.div` ${({ $active }) => ($active ? css.circle(20) : css.circle(16))}; ${css.row('align-both')}; - background-color: ${({ color, bgMode, colorName }) => - !bgMode ? color : theme(`baseColor.${camelize(colorName)}Bg`)}; + background-color: ${({ color, bgMode }) => (!bgMode ? color : baseColorBgTheme(color))}; box-shadow: ${({ $active }) => ($active ? '0px 0px 7px 0px rgb(151 151 151 / 30%)' : '')}; border: ${({ bgMode }) => (bgMode ? '1px dashed' : 'none')}; - border-color: ${({ colorName }) => theme(`baseColor.${camelize(colorName)}`)}; + border-color: ${({ colorName }) => baseColorTheme(colorName)}; &:hover { ${css.circle(20)}; @@ -40,6 +37,5 @@ export const Dot = styled.div` type THookIcon = { colorName: TColorName; bgMode: boolean } export const HookIcon = styled(HookSVG)` ${css.size(10)}; - fill: ${({ bgMode, colorName }) => - !bgMode ? theme('alphaBg2') : theme(`baseColor.${camelize(colorName)}`)}; + fill: ${({ bgMode, colorName }) => (!bgMode ? theme('alphaBg2') : baseColorTheme(colorName))}; ` diff --git a/src/widgets/CommunityDigest/SidebarLayout/index.tsx b/src/widgets/CommunityDigest/SidebarLayout/index.tsx index e4ba89667..eb3497c2d 100644 --- a/src/widgets/CommunityDigest/SidebarLayout/index.tsx +++ b/src/widgets/CommunityDigest/SidebarLayout/index.tsx @@ -79,7 +79,7 @@ const SidebarLayout: FC = () => { - + diff --git a/src/widgets/CommunityDigest/TabberLayout/CommunityBrief.tsx b/src/widgets/CommunityDigest/TabberLayout/CommunityBrief.tsx index 3cea80436..ea4b42f94 100644 --- a/src/widgets/CommunityDigest/TabberLayout/CommunityBrief.tsx +++ b/src/widgets/CommunityDigest/TabberLayout/CommunityBrief.tsx @@ -32,7 +32,7 @@ const CommunityBrief: FC = () => { return ( - + {COVER_IMAGE ? : } diff --git a/src/widgets/CommunityDigest/styles/sidebar_layout/main_menu.ts b/src/widgets/CommunityDigest/styles/sidebar_layout/main_menu.ts index 88c1338f4..f856a6945 100644 --- a/src/widgets/CommunityDigest/styles/sidebar_layout/main_menu.ts +++ b/src/widgets/CommunityDigest/styles/sidebar_layout/main_menu.ts @@ -23,6 +23,8 @@ export const MenuItem = styled(Link)` ${css.row('align-center')}; background: ${({ $active }) => ($active ? theme('hoverBg') : 'transparent')}; width: 160px; + border: 1px solid; + border-color: ${({ $active }) => ($active ? theme('hoverBorder') : 'transparent')}; text-decoration: none; height: 32px; padding-left: 8px; diff --git a/src/widgets/CrashErrorHint/styles/index.ts b/src/widgets/CrashErrorHint/styles/index.ts index d37239527..f31caf059 100755 --- a/src/widgets/CrashErrorHint/styles/index.ts +++ b/src/widgets/CrashErrorHint/styles/index.ts @@ -1,7 +1,7 @@ import styled from 'styled-components' import type { TTestable } from '@/spec' -import { theme, themeSkins } from '@/utils/themes' +import { themeSkins } from '@/utils/themes' import css from '@/css' type TThemeName = { @@ -16,8 +16,6 @@ export const Wrapper = styled.div.attrs(({ testid }) => ({ width: 100%; color: #6b7f83; background: #072d3a; - - /* background: ${theme('thread.bg')}; */ ` export const Header = styled.div` ${css.row()}; diff --git a/src/widgets/CustomHeaderLinks/styles/header_layout.ts b/src/widgets/CustomHeaderLinks/styles/header_layout.ts index b7ca31f99..3006ac2ef 100644 --- a/src/widgets/CustomHeaderLinks/styles/header_layout.ts +++ b/src/widgets/CustomHeaderLinks/styles/header_layout.ts @@ -17,7 +17,7 @@ export const GroupItem = styled(LinkItem)` ${css.row('align-center')}; position: relative; padding-right: 22px; - background: ${({ $active }) => ($active ? theme('hoverBg') : theme(''))}; + background: ${({ $active }) => ($active ? theme('hoverBg') : '')}; &:hover { background: ${theme('hoverBg')}; diff --git a/src/widgets/CustomHeaderLinks/styles/sidebar_layout.ts b/src/widgets/CustomHeaderLinks/styles/sidebar_layout.ts index 5e01ba537..c046f4165 100644 --- a/src/widgets/CustomHeaderLinks/styles/sidebar_layout.ts +++ b/src/widgets/CustomHeaderLinks/styles/sidebar_layout.ts @@ -39,7 +39,7 @@ export const GroupItem = styled(LinkItem)` height: 28px; margin-top: 2px; margin-bottom: 2px; - background: ${({ $active }) => ($active ? theme('hoverBg') : theme(''))}; + background: ${({ $active }) => ($active ? theme('hoverBg') : '')}; &:hover { background: ${theme('hoverBg')}; diff --git a/src/widgets/CustomHeaderLinks/styles/tabber_layout.ts b/src/widgets/CustomHeaderLinks/styles/tabber_layout.ts index a1b769d98..cb55d5b82 100644 --- a/src/widgets/CustomHeaderLinks/styles/tabber_layout.ts +++ b/src/widgets/CustomHeaderLinks/styles/tabber_layout.ts @@ -20,7 +20,7 @@ export const GroupItem = styled(LinkItem)` ${css.row('align-center')}; position: relative; padding-right: 22px; - background: ${({ $active }) => ($active ? theme('hoverBg') : theme(''))}; + background: ${({ $active }) => ($active ? theme('hoverBg') : '')}; &:hover { background: ${theme('hoverBg')}; diff --git a/src/widgets/CustomScroller/HorizontalScroller.tsx b/src/widgets/CustomScroller/HorizontalScroller.tsx index 4933e2497..d54914e75 100755 --- a/src/widgets/CustomScroller/HorizontalScroller.tsx +++ b/src/widgets/CustomScroller/HorizontalScroller.tsx @@ -5,13 +5,12 @@ */ import { FC, useState, useRef, useCallback, memo } from 'react' -import { useTheme } from 'styled-components' import { Waypoint } from 'react-waypoint' -import type { TThemeMap } from '@/spec' import useCustomScroll from '@/hooks/useCustomScroll' // import ViewportTracker from '@/widgets/ViewportTracker' import SIZE from '@/constant/size' +import useTheme from '@/hooks/useTheme' import type { TProps as TScrollProps } from '.' @@ -56,7 +55,8 @@ const HorizontalScroller: FC = ({ const handleHideRightShadow = useCallback(() => setShowRightShadow(false), []) // @ts-ignore - const { _meta: themeMeta }: TThemeMap = useTheme() + const { themeMap } = useTheme() + const { _meta: themeMeta } = themeMap const { category: themeCategory } = themeMeta const ref = useRef(null) diff --git a/src/widgets/CustomScroller/VerticalScroller.tsx b/src/widgets/CustomScroller/VerticalScroller.tsx index c5f416091..119cca889 100755 --- a/src/widgets/CustomScroller/VerticalScroller.tsx +++ b/src/widgets/CustomScroller/VerticalScroller.tsx @@ -5,15 +5,15 @@ */ import { FC, useState, useRef, useCallback, memo } from 'react' -import { useTheme } from 'styled-components' // NOTE: do not use ViewportTracker here, it cause crash import { Waypoint } from 'react-waypoint' -import type { TThemeMap } from '@/spec' import SIZE from '@/constant/size' import { debounce } from '@/helper' import useCustomScroll from '@/hooks/useCustomScroll' +import useTheme from '@/hooks/useTheme' + // import ViewportTracker from '@/widgets/ViewportTracker' import type { TProps as TScrollProps } from '.' @@ -74,7 +74,8 @@ const VerticalScroller: FC = ({ }, [onBottomEnter]) // @ts-ignore - const { _meta: themeMeta }: TThemeMap = useTheme() + const { themeMap } = useTheme() + const { _meta: themeMeta } = themeMap const { category: themeCategory } = themeMeta const ref = useRef(null) diff --git a/src/widgets/Dropdown/styles/index.ts b/src/widgets/Dropdown/styles/index.ts index ac00bccfc..383b02591 100755 --- a/src/widgets/Dropdown/styles/index.ts +++ b/src/widgets/Dropdown/styles/index.ts @@ -7,7 +7,7 @@ type TSize = { size: string } export const Wrapper = styled.div` ${css.row()}; font-size: ${({ size }) => size}; - background: ${theme('dropdown.bg')}; + background: ${theme('button.fg')}; padding: 0 3px; border-radius: 5px; cursor: pointer; diff --git a/src/widgets/FaIcons/styles/panel.ts b/src/widgets/FaIcons/styles/panel.ts index c8c986c01..f35d06dcd 100644 --- a/src/widgets/FaIcons/styles/panel.ts +++ b/src/widgets/FaIcons/styles/panel.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TActive, TColorName } from '@/spec' import { COLORS } from '@/constant/colors' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' import FormInput from '@/widgets/Input' @@ -74,13 +73,12 @@ export const ColorBlock = styled.div` ${css.size(24)}; ${css.row('align-both')}; border-radius: 6px; - background: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background: ${({ color }) => baseColorBgTheme(color)}; border: 1px dotted; - border-color: ${({ $active, color }) => - $active ? theme(`baseColor.${camelize(color)}`) : 'transparent'}; + border-color: ${({ $active, color }) => ($active ? baseColorTheme(color) : 'transparent')}; &:hover { - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + border-color: ${({ color }) => baseColorTheme(color)}; cursor: pointer; } transition: all 0.25s; diff --git a/src/widgets/FaIcons/styles/selector.ts b/src/widgets/FaIcons/styles/selector.ts index e4655a019..adb479178 100644 --- a/src/widgets/FaIcons/styles/selector.ts +++ b/src/widgets/FaIcons/styles/selector.ts @@ -4,8 +4,7 @@ import type { TTestable, TSpace, TColorName, TActive } from '@/spec' import ArrowSVG from '@/icons/ArrowSolid' -import { camelize } from '@/fmt' -import css, { theme } from '@/css' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' type TWrapper = TTestable & TSpace @@ -25,15 +24,14 @@ export const InnerWrapper = styled.div` type TIconWrapper = { color: TColorName } & TActive export const IconWrapper = styled.div` border: 1px dotted; - border-color: ${({ $active, color }) => - $active ? theme(`baseColor.${camelize(color)}`) : 'transparent'}; - background: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + border-color: ${({ $active, color }) => ($active ? baseColorTheme(color) : 'transparent')}; + background: ${({ color }) => baseColorBgTheme(color)}; ${css.size(35)}; ${css.row('align-both')}; border-radius: 7px; ${InnerWrapper}:hover & { - border-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + border-color: ${({ color }) => baseColorTheme(color)}; } ` export const ArrowIcon = styled(ArrowSVG)` diff --git a/src/widgets/Facepile/styles/real_avatar.ts b/src/widgets/Facepile/styles/real_avatar.ts index 1fbae8980..2bf1c0f14 100755 --- a/src/widgets/Facepile/styles/real_avatar.ts +++ b/src/widgets/Facepile/styles/real_avatar.ts @@ -40,7 +40,7 @@ type TAvatarsImg = { } export const AvatarsImg = styled(Img)` border: 2px solid; - border-color: ${theme('thread.commentsUserBorder')}; + border-color: ${theme('divider')}; color: #ffffff; font-size: 12px; font-weight: 100; diff --git a/src/widgets/FaqList/styles/search_hint.ts b/src/widgets/FaqList/styles/search_hint.ts index c4b4c84db..763795744 100755 --- a/src/widgets/FaqList/styles/search_hint.ts +++ b/src/widgets/FaqList/styles/search_hint.ts @@ -3,8 +3,7 @@ import Link from 'next/link' import type { TColorName, TTestable } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme } from '@/css' import FAQSVG from '@/icons/FAQ' @@ -72,7 +71,7 @@ export const CatSection = styled.div<{ color: TColorName }>` height: 100%; width: 4px; border-radius: 5px; - background-color: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + background-color: ${({ color }) => baseColorTheme(color)}; opacity: 0.5; } ` diff --git a/src/widgets/Footer/DesktopView/GroupLayout.tsx b/src/widgets/Footer/DesktopView/GroupLayout.tsx index 5bc060f35..875a24619 100644 --- a/src/widgets/Footer/DesktopView/GroupLayout.tsx +++ b/src/widgets/Footer/DesktopView/GroupLayout.tsx @@ -1,10 +1,9 @@ import { FC } from 'react' import { observer } from 'mobx-react' -import { useTheme } from 'styled-components' import { keys } from 'ramda' -import type { TThemeMap } from '@/spec' import { DEME_SOCIALS } from '@/constant/social' +import useTheme from '@/hooks/useTheme' import useViewingCommunity from '@/hooks/useViewingCommunity' import useFooterLinks from '@/hooks/useFooterLinks' @@ -26,13 +25,13 @@ import { } from '../styles/desktop_view/group_layout' const GroupLayout: FC = () => { - const theme = useTheme() as TThemeMap + const { themeMap } = useTheme() const curCommunity = useViewingCommunity() const { links } = useFooterLinks() const linkColors = { - color: theme.footer.text, - hoverColor: theme.footer.hover, + color: themeMap.footer.text, + hoverColor: themeMap.footer.hover, } // @ts-ignore diff --git a/src/widgets/Footer/styles/index.ts b/src/widgets/Footer/styles/index.ts index 291ef105e..a265ec876 100644 --- a/src/widgets/Footer/styles/index.ts +++ b/src/widgets/Footer/styles/index.ts @@ -1,7 +1,7 @@ import styled from 'styled-components' import type { TTestable, TMetric } from '@/spec' -import css from '@/css' +import css, { theme } from '@/css' type TWrapper = TTestable & { metric?: TMetric } export const Wrapper = styled.div.attrs(({ testid }) => ({ @@ -13,7 +13,7 @@ export const Wrapper = styled.div.attrs(({ testid }) => ({ margin-top: 80px; padding-top: 50px; padding-bottom: 30px; - box-shadow: rgb(241 241 241) 0px 0px 50px 0px inset; + box-shadow: ${theme('footer.shadow')}; ${css.media.mobile` margin-top: 40px; diff --git a/src/widgets/Icons/Moon.tsx b/src/widgets/Icons/Moon.tsx new file mode 100644 index 000000000..eca33cd77 --- /dev/null +++ b/src/widgets/Icons/Moon.tsx @@ -0,0 +1,11 @@ +import { memo, SVGProps } from 'react' + +const SVG = (props: SVGProps) => { + return ( + + + + ) +} + +export default memo(SVG) diff --git a/src/widgets/Icons/Sun.tsx b/src/widgets/Icons/Sun.tsx new file mode 100644 index 000000000..bacf5211b --- /dev/null +++ b/src/widgets/Icons/Sun.tsx @@ -0,0 +1,11 @@ +import { memo, SVGProps } from 'react' + +const SVG = (props: SVGProps) => { + return ( + + + + ) +} + +export default memo(SVG) diff --git a/src/widgets/ImgFallback/styles/avatar.ts b/src/widgets/ImgFallback/styles/avatar.ts index 99cbc830b..d46fc6f9f 100755 --- a/src/widgets/ImgFallback/styles/avatar.ts +++ b/src/widgets/ImgFallback/styles/avatar.ts @@ -3,8 +3,7 @@ import styled from 'styled-components' import type { TAvatarLayout, TColorName, TTestable } from '@/spec' import { AVATAR_LAYOUT } from '@/constant/layout' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme, baseColorBgTheme } from '@/css' import type { TAvatarProps } from '..' import { getFontSize } from './metric/avatar' @@ -16,7 +15,7 @@ export const Wrapper = styled.div.attrs(({ testid }) => ({ }))` ${css.row('align-both')}; - background: ${({ color }) => theme(`baseColor.${camelize(color)}Bg`)}; + background: ${({ color }) => baseColorBgTheme(color)}; width: ${({ size }) => `${size}px`}; height: ${({ size }) => `${size}px`}; @@ -35,6 +34,6 @@ export const Wrapper = styled.div.attrs(({ testid }) => ({ ` type TName = { size: number; color: TColorName } export const Name = styled.div` - color: ${({ color }) => theme(`baseColor.${color?.toLowerCase()}`)}; + color: ${({ color }) => baseColorTheme(color)}; font-size: ${({ size }) => getFontSize(size)}; ` diff --git a/src/widgets/Loading/ArticleContentLoading.tsx b/src/widgets/Loading/ArticleContentLoading.tsx index 3f7bcbf51..bb1d78105 100755 --- a/src/widgets/Loading/ArticleContentLoading.tsx +++ b/src/widgets/Loading/ArticleContentLoading.tsx @@ -1,9 +1,10 @@ import { FC, memo } from 'react' import { range } from 'ramda' -import { useTheme } from 'styled-components' import ContentLoader from 'react-content-loader' import type { TSpace } from '@/spec' +import useTheme from '@/hooks/useTheme' + import { Wrapper, LoadingWrapper } from './styles/article_content_loading' const LoadingItem = ({ theme }) => ( @@ -11,7 +12,9 @@ const LoadingItem = ({ theme }) => ( height={100} width={400} speed={2} - foregroundColor={theme.loading.basic} + foregroundColor={theme.divider} + backgroundColor={theme.divider} + backgroundOpacity={0.5} > @@ -25,13 +28,13 @@ const LoadingItem = ({ theme }) => ( type TProps = TSpace & { num?: number } const ArticleContentLoading: FC = ({ num = 1, ...restProps }) => { - const theme = useTheme() + const { themeMap } = useTheme() return ( {range(0, num).map((item) => ( - + ))} diff --git a/src/widgets/PostItem/QuoraLayout/DesktopView/Header.tsx b/src/widgets/PostItem/QuoraLayout/DesktopView/Header.tsx index dea9aceda..a6ad55a63 100644 --- a/src/widgets/PostItem/QuoraLayout/DesktopView/Header.tsx +++ b/src/widgets/PostItem/QuoraLayout/DesktopView/Header.tsx @@ -5,7 +5,9 @@ import TimeAgo from 'timeago-react' import type { TPost } from '@/spec' import useViewingCommunity from '@/hooks/useViewingCommunity' +import useBannerLayout from '@/hooks/useBannerLayout' import { THREAD } from '@/constant/thread' +import { BANNER_LAYOUT } from '@/constant/layout' import SIZE from '@/constant/size' import Tooltip from '@/widgets/Tooltip' @@ -33,6 +35,7 @@ type TProps = { const Header: FC = ({ article }) => { const { slug } = useViewingCommunity() + const bannerLayout = useBannerLayout() const { author, title, commentsCount, innerId, articleTags, insertedAt } = article return ( @@ -59,7 +62,13 @@ const Header: FC = ({ article }) => { {/* @ts-ignore */} - {commentsCount !== 0 && } + {commentsCount !== 0 && ( + + )} ) diff --git a/src/widgets/PostItem/styles/cover_layout/index.ts b/src/widgets/PostItem/styles/cover_layout/index.ts index df38fa91c..a3e0f36dc 100644 --- a/src/widgets/PostItem/styles/cover_layout/index.ts +++ b/src/widgets/PostItem/styles/cover_layout/index.ts @@ -14,7 +14,7 @@ export const Wrapper = styled.article` padding-top: ${({ c11n }) => (c11n.contentDivider ? '10px' : '8px')}; padding-bottom: ${({ c11n }) => (c11n.contentDivider ? '14px' : '8px')}; border-bottom: ${({ c11n }) => (c11n.contentDivider ? '1px solid' : '0')}; - border-bottom-color: ${theme('thread.articleDivider')}; + border-bottom-color: ${theme('divider')}; margin-bottom: 5px; transition: all 0.2s; diff --git a/src/widgets/PostItem/styles/index.ts b/src/widgets/PostItem/styles/index.ts index b7214e75c..d701fc7ea 100644 --- a/src/widgets/PostItem/styles/index.ts +++ b/src/widgets/PostItem/styles/index.ts @@ -29,6 +29,7 @@ export const DesktopHoverable = styled.div` border-radius: 10px; z-index: -1; opacity: 0; + transition: all 0.2s; } ${css.media.mobile` diff --git a/src/widgets/PromotionList/styles/index.ts b/src/widgets/PromotionList/styles/index.ts index 91d1e20f0..44eacd6be 100755 --- a/src/widgets/PromotionList/styles/index.ts +++ b/src/widgets/PromotionList/styles/index.ts @@ -13,7 +13,7 @@ export const Header = styled.div` margin-bottom: 12px; padding-top: 20px; border-top: 1px solid; - border-top-color: ${theme('thread.articleSpliter')}; + border-top-color: ${theme('divider')}; width: 100%; ` export const Title = styled.div` diff --git a/src/widgets/PromptIcon/PlanetDriver.tsx b/src/widgets/PromptIcon/PlanetDriver.tsx index 87a1e245d..82a951398 100755 --- a/src/widgets/PromptIcon/PlanetDriver.tsx +++ b/src/widgets/PromptIcon/PlanetDriver.tsx @@ -1,10 +1,9 @@ import { FC, memo } from 'react' -import { useTheme } from 'styled-components' -import type { TThemeMap } from '@/spec' import { ICON_BASE } from '@/config' - +import useTheme from '@/hooks/useTheme' import { getRandomInt } from '@/helper' + import { PlanetDriverIcon } from './styles' const getRandomAngle = () => rotateAngles[getRandomInt(0, rotateAngles.length - 1)] @@ -29,12 +28,12 @@ type TProps = { } const PlanetDriver: FC = ({ className }) => { - const theme = useTheme() as TThemeMap + const { themeMap } = useTheme() return ( ) diff --git a/src/widgets/Select/index.tsx b/src/widgets/Select/index.tsx index 041f56379..e3171a60c 100755 --- a/src/widgets/Select/index.tsx +++ b/src/widgets/Select/index.tsx @@ -7,12 +7,12 @@ */ import { FC, memo } from 'react' -import { useTheme } from 'styled-components' import ReactSelect from 'react-select' import CreatableReactSelect from 'react-select/creatable' -import type { TSelectOption, TThemeMap } from '@/spec' +import type { TSelectOption } from '@/spec' import { buildLog } from '@/logger' +import useTheme from '@/hooks/useTheme' import { IndicatorsContainer } from './components' @@ -51,8 +51,8 @@ const Select: FC = ({ onCreateOption = log, }) => { // @ts-ignore - const theme: TThemeMap = useTheme() - const styles = getSelectStyles(theme) + const { themeMap } = useTheme() + const styles = getSelectStyles(themeMap) const baseProps = { value, diff --git a/src/widgets/TagSelector/styles/filter_panel.ts b/src/widgets/TagSelector/styles/filter_panel.ts index 0646183ca..4f15b4f6a 100644 --- a/src/widgets/TagSelector/styles/filter_panel.ts +++ b/src/widgets/TagSelector/styles/filter_panel.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TActive } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme } from '@/css' import { SelectItem as SelectItemBase } from '.' @@ -29,7 +28,7 @@ export const DotBox = styled.div` type THashSign = TActive & { color?: string } export const DotSign = styled.div` ${css.circle(7)}; - background: ${({ color }) => (color ? theme(`baseColor.${camelize(color)}`) : 'none')}; + background: ${({ color }) => (color ? baseColorTheme(color) : 'none')}; margin-right: 8px; margin-top: -1px; diff --git a/src/widgets/TagsList/styles/index.ts b/src/widgets/TagsList/styles/index.ts index 098241692..2871ca7e8 100755 --- a/src/widgets/TagsList/styles/index.ts +++ b/src/widgets/TagsList/styles/index.ts @@ -2,8 +2,7 @@ import styled from 'styled-components' import type { TSizeTSM, TSpace } from '@/spec' -import css, { theme } from '@/css' -import { camelize } from '@/fmt' +import css, { theme, baseColorTheme } from '@/css' import { getIconSize, getTitleSize, getInnerSpace } from './metric' @@ -24,13 +23,13 @@ export const Tag = styled.div` ` type THashSign = { color: string; size: TSizeTSM } export const DotSign = styled.div` - background: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + background: ${({ color }) => baseColorTheme(color)}; ${({ size }) => css.circle(getIconSize(size))}; margin-right: 2px; margin-right: ${({ size }) => `${getInnerSpace(size)}px`}; ` export const LabelDotSign = styled.div` - background: ${({ color }) => theme(`baseColor.${camelize(color)}`)}; + background: ${({ color }) => baseColorTheme(color)}; ${css.circle(8)}; margin-right: 4px; ` diff --git a/src/widgets/ThemeSelector/CardSelector.tsx b/src/widgets/ThemeSelector/CardSelector.tsx index 77dd7ec0e..c920fba64 100755 --- a/src/widgets/ThemeSelector/CardSelector.tsx +++ b/src/widgets/ThemeSelector/CardSelector.tsx @@ -1,6 +1,7 @@ import { FC, memo } from 'react' import { keys } from 'ramda' +import type { TThemeName } from '@/spec' import { ICON_CMD } from '@/config' import { themeMeta } from '@/utils/themes' @@ -17,7 +18,7 @@ import { } from './styles/card_selector' type TProps = { - curTheme?: string + curTheme?: TThemeName changeTheme?: (theme: string) => void } @@ -25,21 +26,12 @@ const CardSelector: FC = ({ curTheme, changeTheme }) => ( {keys(themeMeta).map((name) => ( - changeTheme(name)} - /> + changeTheme(name)} /> - changeTheme(name)} - > + changeTheme(name)}> {name} - changeTheme(name)}> - {themeMeta[name].desc} - + changeTheme(name)}>{themeMeta[name].desc} = ({ displayStyle, curTheme, changeTheme }) => { switch (displayStyle) { case 'card': { - return + return } case 'gallery': { - return + return } default: { - return + return } } } diff --git a/src/widgets/ThemeSelector/styles/index.ts b/src/widgets/ThemeSelector/styles/index.ts index 5b0581396..3c3851aec 100755 --- a/src/widgets/ThemeSelector/styles/index.ts +++ b/src/widgets/ThemeSelector/styles/index.ts @@ -4,13 +4,15 @@ import type { TActive, TThemeName } from '@/spec' import { theme, themeCoverMap, themeCoverIndexMap } from '@/utils/themes' import css from '@/css' +import THEME from '@/constant/theme' + type TDot = TActive & { name: TThemeName } export const Dot = styled.div` ${css.circle(25)}; margin-right: 10px; background: ${({ name }) => themeCoverMap[name]}; - border: ${({ name }) => (name === 'github' ? '1px solid lightgrey' : '')}; + border: ${({ name }) => (name === THEME.DAY ? '1px solid lightgrey' : '')}; position: relative; cursor: pointer; color: ${({ active, name }) => (active ? theme('bodyBg') : themeCoverMap[name])}; diff --git a/src/widgets/ThemeSwitch/index.tsx b/src/widgets/ThemeSwitch/index.tsx new file mode 100644 index 000000000..a0af552b5 --- /dev/null +++ b/src/widgets/ThemeSwitch/index.tsx @@ -0,0 +1,42 @@ +/* + * ThemeSwitch + */ + +import { FC } from 'react' +import { observer } from 'mobx-react' + +import type { TSpace } from '@/spec' +import useTheme from '@/hooks/useTheme' + +import { buildLog } from '@/logger' +import THEME from '@/constant/theme' + +import { Wrapper, Button, SunIcon, MoonIcon } from './styles' + +/* eslint-disable-next-line */ +const log = buildLog('c:ThemeSwitch:index') + +type TProps = { + testid?: string +} & TSpace + +const ThemeSwitch: FC = ({ testid = 'theme-switch', ...restProps }) => { + const { curTheme, changeTheme } = useTheme() + + return ( + + + + ) +} + +export default observer(ThemeSwitch) diff --git a/src/widgets/ThemeSwitch/styles/index.ts b/src/widgets/ThemeSwitch/styles/index.ts new file mode 100644 index 000000000..6d909944f --- /dev/null +++ b/src/widgets/ThemeSwitch/styles/index.ts @@ -0,0 +1,67 @@ +import styled from 'styled-components' + +import type { TSpace, TTestable } from '@/spec' + +import SunSVG from '@/icons/Sun' +import MoonSVG from '@/icons/Moon' + +import css, { theme } from '@/css' + +type TWrapper = TTestable & TSpace +export const Wrapper = styled.div.attrs(({ testid }) => ({ + 'data-test-id': testid, +}))` + ${(props) => css.spaceMargins(props)}; +` + +export const Button = styled.button` + ${css.row('align-both')}; + background: none; + border: none; + padding: 0; + + inline-size: 22px; + block-size: 22px; + aspect-ratio: 1; + border-radius: 5px; + + touch-action: manipulation; + -webkit-tap-highlight-color: transparent; + outline-offset: 5px; + + &:hover { + background: ${theme('hoverBg')}; + cursor: pointer; + } +` + +export const SunIcon = styled(SunSVG)` + ${css.size(18)}; + fill: ${theme('article.digest')}; + + ${Button}:hover & { + fill: ${theme('article.title')}; + transform: rotate(90deg); + } + &:active { + transform: scale(0.7); + } + + transition: all 0.2s; +` + +export const MoonIcon = styled(MoonSVG)` + ${css.size(18)}; + fill: ${theme('article.digest')}; + + ${Button}:hover & { + fill: ${theme('article.title')}; + transform: rotate(-180deg); + } + + &:active { + transform: scale(0.7); + } + + transition: all 0.2s; +` diff --git a/src/widgets/ThemeSwitch/tests/index.test.ts b/src/widgets/ThemeSwitch/tests/index.test.ts new file mode 100644 index 000000000..a258eb00d --- /dev/null +++ b/src/widgets/ThemeSwitch/tests/index.test.ts @@ -0,0 +1,10 @@ +// import React from 'react' +// import { shallow } from 'enzyme' + +// import ThemeSwitch from '..' + +describe('TODO ', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(true) + }) +}) diff --git a/src/widgets/Tooltip/styles/index.ts b/src/widgets/Tooltip/styles/index.ts index a67901e77..30923c885 100755 --- a/src/widgets/Tooltip/styles/index.ts +++ b/src/widgets/Tooltip/styles/index.ts @@ -9,16 +9,14 @@ export const StyledTippy = styled(Tippy)<{ wechatEnv?: boolean }>` box-shadow: ${theme('popover.boxShadow')}; outline: none; max-width: 480px !important; - border: 1px solid; - border-color: ${theme('popover.borderColor')}; border-radius: 5px; padding: 5px; - box-shadow: -3px 2px 20px 0px rgb(58 58 58 / 15%); + border: 1px solid; border-color: ${theme('divider')}; - background: ${({ wechatEnv }) => (wechatEnv ? theme('alphaBg2') : theme('popover.bg'))}; + // background: ${({ wechatEnv }) => (wechatEnv ? theme('alphaBg2') : theme('popover.bg'))}; backdrop-filter: blur(5px); .tippy-arrow { diff --git a/src/widgets/TrendLine/index.tsx b/src/widgets/TrendLine/index.tsx index 34a06429b..425068072 100755 --- a/src/widgets/TrendLine/index.tsx +++ b/src/widgets/TrendLine/index.tsx @@ -6,10 +6,9 @@ import { FC, memo } from 'react' import Trend from 'react-trend' -import { useTheme } from 'styled-components' -import type { TThemeMap } from '@/spec' import { buildLog } from '@/logger' +import useTheme from '@/hooks/useTheme' /* eslint-disable-next-line */ const log = buildLog('w:TrendLine:index') @@ -21,11 +20,11 @@ type TProps = { } const TrendLine: FC = ({ data, radius = 15, width = 5 }) => { - const theme = useTheme() as TThemeMap + const { themeMap } = useTheme() const { heatmap: { activityLow, activityHight }, - } = theme + } = themeMap return ( (({ testid }) => ({ export const Button = styled.div` ${css.row('align-center')}; border: 1px solid; - border-color: ${theme('button.upvoteBorder')}; + border-color: ${theme('divider')}; margin-right: 16px; border-radius: 10px; diff --git a/utils/constant/index.ts b/utils/constant/index.ts index e13ad73a1..990bcfa04 100755 --- a/utils/constant/index.ts +++ b/utils/constant/index.ts @@ -52,3 +52,5 @@ export { export { PUBLISH_MODE } from './publish' export { COLORS, COLOR_NAME } from './colors' + +export { default as THEME } from './theme' diff --git a/utils/constant/theme.ts b/utils/constant/theme.ts new file mode 100644 index 000000000..f6f578cac --- /dev/null +++ b/utils/constant/theme.ts @@ -0,0 +1,8 @@ +import type { TThemeName } from '@/spec' + +const THEME = { + DAY: 'day', + NIGHT: 'night', +} as Record, TThemeName> + +export default THEME diff --git a/utils/css/index.ts b/utils/css/index.ts index 632a02501..111536006 100755 --- a/utils/css/index.ts +++ b/utils/css/index.ts @@ -74,7 +74,14 @@ const css = { spaceMargins, } -export { theme, primaryTheme, primaryLightTheme, primaryLink } from '../themes' +export { + theme, + primaryTheme, + primaryLightTheme, + primaryLink, + baseColorTheme, + baseColorBgTheme, +} from '../themes' export { WIDTH } from './metric' export { default as zIndex } from './zindex' diff --git a/utils/index.ts b/utils/index.ts index 5c215d6a3..476ae5d9f 100755 --- a/utils/index.ts +++ b/utils/index.ts @@ -107,7 +107,15 @@ export { /* * theme related */ -export { theme, themeMeta, themeSkins, themeCoverMap, themeCoverIndexMap } from './themes' +export { + theme, + themeMeta, + themeSkins, + themeCoverMap, + themeCoverIndexMap, + baseColorTheme, + baseColorBgTheme, +} from './themes' // helpers export { default as css } from './css' diff --git a/utils/themes/index.ts b/utils/themes/index.ts index 678d17037..8b448e6cc 100755 --- a/utils/themes/index.ts +++ b/utils/themes/index.ts @@ -18,6 +18,7 @@ import { COLORS, COLOR_NAME } from '@/constant/colors' import { camelize } from '@/fmt' +import type { TFlatThemeKey } from './skins' import skinsData from './skins' export const themeSkins = { ...skinsData } @@ -30,15 +31,15 @@ export const themeCoverMap = map(path(['cover']), themeSkins) export const themeCoverIndexMap = map(path(['coverIndex']), themeSkins) // curried shorthand for style-components -export const theme = (themePath: string): TTheme => - path(['theme', ...split('.', themePath)]) || 'wheat' +export const theme = (themeKey: TFlatThemeKey): TTheme => + path(['theme', ...split('.', themeKey)]) || 'wheat' /** * for primary color component */ export const primaryTheme = (primaryColor: TColorName, themeKey = 'primary'): string => { if (primaryColor === COLOR_NAME.BLACK) { - return theme(themeKey) + return theme(themeKey as TFlatThemeKey) } return COLORS[primaryColor] @@ -57,6 +58,15 @@ export const primaryLightTheme = (primaryColor: TColorName): string => { return theme('hoverBg') } - return theme(`baseColor.${camelize(primaryColor)}Bg`) + return `baseColor.${camelize(primaryColor)}Bg` as TFlatThemeKey } + +export const baseColorTheme = (color: TColorName | string): string => { + return theme(`baseColor.${camelize(color)}` as TFlatThemeKey) +} + +export const baseColorBgTheme = (color: TColorName | string): string => { + return theme(`baseColor.${camelize(color)}Bg` as TFlatThemeKey) +} + export { default as themeMeta } from './theme_meta' diff --git a/utils/themes/skins/github.ts b/utils/themes/skins/day.ts old mode 100755 new mode 100644 similarity index 96% rename from utils/themes/skins/github.ts rename to utils/themes/skins/day.ts index b0ee4f7fb..4b76962fa --- a/utils/themes/skins/github.ts +++ b/utils/themes/skins/day.ts @@ -1,10 +1,9 @@ /* - * a theme inspired by github + * light mode */ import { lighten, darken } from '@/utils/color' const primaryColor = '#333333' // '#000000' - const bannerBg = '#fff' const contentBg = '#fff' const contentBoxBg = '#fff' @@ -20,11 +19,11 @@ const hoverBg = '#efefef9c' // with alpha const hint = '#9d9999' // const primaryMate = 'orange' -const github = { +const day = { _meta: { category: 'light', }, - name: 'github', + name: 'day', primary: primaryColor, logoText: descText, cover: 'white', @@ -48,6 +47,7 @@ const github = { alphaBg: '#ffffff95', alphaBg2: '#fffffff2', hoverBg, + hoverBorder: hoverBg, hoverLinear: 'linear-gradient(315deg, rgba(255, 255, 255, 0) 0%, #fafafa 100%)', activeLinear: 'linear-gradient(315deg,rgba(255,255,255,0) 0%,#f1f1f1 70%)', menuActive: '#e9e9e991', @@ -136,12 +136,6 @@ const github = { reactionTitle: '#7f979a', reactionHoverBg: '#f3f7f7', }, - thread: { - bg: contentBoxBg, - articleDivider: '#dce5e6', - commentsUserBorder: contentBoxBg, - articleSpliter: '#dee8ea', - }, content: { bg: contentBoxBg, border: '#EEEEEE', @@ -154,6 +148,7 @@ const github = { hover: '#949CB5', title: '#77706B', bottomBg: '#252325', + shadow: 'rgb(241 241 241) 0px 0px 50px 0px inset', }, drawer: { title: threadTitle, @@ -213,7 +208,6 @@ const github = { footer: '#a6bebf', footerHover: darken('#a6bebf', 5), }, - markdown: { title: primaryColor, fg: markdownFont, @@ -262,7 +256,7 @@ const github = { popover: { bg: '#ffffffd9', borderColor: '#e9e9ea', - boxShadow: '0 1px 4px rgba(0, 0, 0, 0.15)', + boxShadow: '-3px 2px 20px 0px rgb(58 58 58 / 15%)', activeBorder: '#70707094', }, tags: { @@ -337,4 +331,4 @@ const github = { }, } -export default github +export default day diff --git a/utils/themes/skins/index.ts b/utils/themes/skins/index.ts index b5c273b37..1efddf865 100755 --- a/utils/themes/skins/index.ts +++ b/utils/themes/skins/index.ts @@ -11,24 +11,17 @@ * Earthsung https://atom.io/themes/earthsung-by-jackson-syntax */ -// import cyan from './cyan' -// import solarizedDark from './solarized_dark' -import github from './github' -// import purple from './purple' -// import monokai from './monokai' -// import yellow from './yellow' -// import green from './green' -// import ironGreen from './iron_green' +import type { TFlattenObjectKeys } from '@/spec' + +import day from './day' +import night from './night' const skinsData = { - // cyan, - // solarizedDark, - // purple, - // yellow, - github, - // monokai, - // green, - // ironGreen, + day, + night, } +// see https://www.raygesualdo.com/posts/flattening-object-keys-with-typescript-types +export type TFlatThemeKey = TFlattenObjectKeys + export default skinsData diff --git a/utils/themes/skins/night.ts b/utils/themes/skins/night.ts new file mode 100644 index 000000000..b76151c6f --- /dev/null +++ b/utils/themes/skins/night.ts @@ -0,0 +1,334 @@ +/* + * dark mode + */ +import { lighten, darken } from '@/utils/color' + +const primaryColor = '#333333' // '#000000' +const bannerBg = '#222222' // '#161616' +const contentBg = '#222222' // '#161616' +const contentBoxBg = '#222222' // '#161616' +const fontColor = primaryColor +const markdownFont = '#9eb8bd' +const border = '#3c3c3c' // '#282828' +const link = '#005196' // '#6494cd' + +const actionText = '#7f8695' +const descText = '#7c7f82' +const threadTitle = '#FFFFFF' +const hoverBg = '#42424259' // with alpha +const hint = '#9d9999' +// const primaryMate = 'orange' + +const night = { + _meta: { + category: 'night', + }, + name: 'night', + primary: primaryColor, + logoText: descText, + cover: 'white', + coverIndex: '#F9FCFC', + contrastFg: '#eca014', + htmlBg: bannerBg, + spaceBg: '#fff', + mobileTab: '#323344', + loading: { + basic: '#E0E0E0', + animate: contentBg, + }, + error: { + title: primaryColor, + desc: darken(primaryColor, 10), + bg: lighten(contentBoxBg, 2), + }, + font: fontColor, + link, + divider: border, + alphaBg: hoverBg, + alphaBg2: '#1c1c1cb8', + hoverBg, + hoverBorder: '#393939', + hoverLinear: 'linear-gradient(315deg, rgb(104 104 104 / 0%) 0%, #2c2c2c 100%);', + activeLinear: 'linear-gradient(315deg,rgba(255,255,255,0) 0%,#f1f1f1 70%)', + menuActive: '#e9e9e991', + linkHover: lighten(link, 5), + heightIcon: '#e48a3d', + heightGradient: 'linear-gradient(90deg, rgb(243, 170, 0) 0%, rgb(228, 62, 41) 100%)', + main: '#7DC0C5', + bodyBg: contentBg, + selectionBg: '#FFFEDE', + textBadge: '#e2e2e287', // with alpha + lightText: '#999999', + hint, + + baseColor: { + red: '#ca5f4d', + redBg: '#ffbfba3d', + + orange: '#ce9f6f', + orangeBg: '#FEF7E8', + + brown: '#8d691e', + brownBg: '#fff3df', + + yellow: '#eddd85', + yellowBg: '#FEFBE8', + + green: '#699411', + greenBg: '#eefdd89c', + + greenLight: '#37B784', + greenLightBg: '#e3f3cc4a', + + cyan: '#24878C', + cyanBg: '#e1fcff', + + // naming, fix later + cyanLight: '#00B5CC', + cyanLightBg: '#e1fcff94', + + blue: '#0073E3', + blueBg: '#d8e3fd54', + + purple: '#7d519e', + purpleBg: '#f7d8fd38', + + grey: '#106d8a', + + pink: '#b36976', + pinkBg: '#ffd8ea59', + + pinkLite: '#82606b', + pinkBtnText: '#ded0d0', + + black: '#333333', + blackBg: '#f4f4f4', + }, + header: { + fg: '#8c8c8c', + bg: bannerBg, + spliter: '#efefef', + fixed: contentBoxBg, + tabActive: '#EB6224', // articleTitle + tabOthers: lighten('#849ca0', 10), + cardBg: '#ffffff', + cardBorder: '#e6e6e6', + cardLogoText: 'lightgrey', + cardTitle: 'darkgrey', + }, + banner: { + title: threadTitle, + bg: bannerBg, + desc: descText, + spliter: '#eae9e9', + numberDesc: '#cccccc', + number: '#949494', + active: '#669ede', + numberDivider: '#eae9e9', + numberHoverBg: '#f3f3f3', + }, + article: { + title: threadTitle, + digest: descText, + info: actionText, + link, + linkHover: 'orange', + reactionTitle: '#7f979a', + reactionHoverBg: '#f3f7f7', + }, + content: { + bg: contentBoxBg, + border: '#EEEEEE', + cardBg: contentBoxBg, + cardBorder: '#e6e6e6', + cardBorderHover: primaryColor, + }, + footer: { + text: descText, + hover: '#949CB5', + title: '#77706B', + bottomBg: '#252325', + shadow: 'rgb(25 25 25) 0px 0px 50px 0px inset', + }, + drawer: { + title: threadTitle, + mask: 'rgba(31, 34, 37, 0.15)', + desc: descText, + font: primaryColor, + bg: contentBg, + shadow: '-13px 1px 20px 11px rgb(0 0 0 / 9%)', + shadowLite: '-8px 8px 20px 11px rgb(143 143 143 / 2%)', + closerShadow: '-3px 12px 20px 0px rgb(32 29 29 / 83%)', + markdownHelperBg: '#F9FCFC', + accountBg: '#FFFFFF', + articleBg: '#FFFFFF', + helper: '#d9e5e6', + helperHover: '#83a2a5', + topLine: '#22292E', + icon: 'tomato', + divider: '#e0e6e5', + /* single article page sidebar divider */ + sideDivider: '#e4e4e4', + }, + comment: { + bg: contentBg, + icon: 'grey', + didIcon: 'orange', + title: 'grey', + username: '#7FA7AC', + number: '#efbc60', + floor: '#8590a6', + reply: '#93b3b5', + replyBg: '#f3f3f3', + placeholder: '#8c94a3', + filter: 'grey', + filterActive: primaryColor, + action: actionText, + // mention text displayed in article + mentionText: '#91a4b5', + mentionTextBg: '#fcffdb', + // mention popover background + mentionBg: '#F9FCFC', + mentionBorder: primaryColor, + mentionActiveBg: darken('#F9FCFC', 10), + mentionShadow: '0px 2px 10px 1px rgba(235, 235, 235, 1)', + + indentLine: '#E7E9ED', + indentActive: '#B5BCCB', + }, + editor: { + title: '#7ea9ad', + content: '#a6bebf', + placeholder: '#B3CFD0', + headerBg: '#F9FCFC', + contentBg: '#F9FCFC', + border: '#D6D6D6', + borderActive: descText, + borderNormal: '#e2eaea', + footer: '#a6bebf', + footerHover: darken('#a6bebf', 5), + }, + markdown: { + title: primaryColor, + fg: markdownFont, + titleBottom: lighten(primaryColor, 30), + hrColor: '#154452', + blockquoteBorder: '#b8d0ce', + blockquoteFg: darken(markdownFont, 10), + strongFg: '#7c999c', + strongBg: contentBoxBg, + link, + tableBg: darken(contentBoxBg, 5), + tableBg2n: darken(contentBoxBg, 5), + tableborder: `1px solid ${darken(contentBoxBg, 10)}`, + taskDone: '#528416', + taskPeding: darken(contentBoxBg, 10), + br: '#e8e8e8', + }, + code: { + bg: darken(contentBoxBg, 5), + }, + shell: { + link, + searchInput: descText, + searchIcon: lighten(descText, 10), + barBg: contentBoxBg, + border: '#f3f3f3', + title: threadTitle, + desc: descText, + activeBg: '#F5F5F5', + }, + button: { + primary: primaryColor, + fg: 'white', + disabledFg: descText, + hoverBg: lighten(primaryColor, 10), + activeBg: darken(primaryColor, 5), + clicked: primaryColor, + ghostBorder: hint, + upvoteBorder: '#dadada', + }, + navigator: { + activeBottom: primaryColor, + borderRight: darken(bannerBg, 5), + hoverBg: '#eee', + }, + popover: { + bg: 'tomato', // '#ffffffd9', + borderColor: '#e9e9ea', + boxShadow: '-9px 7px 20px 9px rgb(24 24 24 / 44%)', + activeBorder: '#70707094', + }, + tags: { + dotOpacity: 0.7, + text: descText, + }, + tagger: { + text: '#d2a05f', + bg: '#fff2b3', + border: '#fff2b3', + closeBtn: '#d2a05f', + }, + tabs: { + headerActive: '#EB6224', + header: '#b5b5b5', + contentBg: '#FFFFFF', + headerBg: '#F7F9F9', + headerActiveTop: primaryColor, + border: '#E8E8E8', + bottomLine: '#E1E4E8', + }, + modal: { + bg: contentBoxBg, + mask: 'rgba(31, 34, 37, 0.1)', + border: primaryColor, + innerSelectBg: '#e4eeed45', + subPanel: '#F5F5F5', + // subPanelShadow: 'drop-shadow(3px 3px 6px #EAE9E9)', + subPanelShadow: 'none', + }, + form: { + inputBg: '#FFFFFF', + text: '#88a4ad', + label: '#88a4ad', + border: '#B8C6C0', + shadow: 'rgba(184, 198, 192, 0.3)', + }, + a: { + hover: primaryColor, + active: darken(primaryColor, 10), + }, + toast: { + bg: contentBoxBg, + border, + message: descText, + title: threadTitle, + infoBar: '#E8F0FE', + errorBar: '#f59381', + successBar: '#9dd035', + warnBar: '#f5a30e', + boxShadow: '-3px 5px 20px 0px rgb(155 155 155 / 20%)', + }, + mailBox: { + headHightBg: '#e8f9f8', + }, + table: { + headerBg: '#F8F8F8', + headTitle: '#949494', + text: '#949497', + border: '#F0F0F0', + hoverBg: '#FAFBFC', + }, + searchHighlight: { + doramonFg: '#03a9f4', + doramonBg: 'transparent', + }, + avatar: { + opacity: 1, + quote: '#217470', + shadow: '0px 0px 4px 0px rgb(0 0 0 / 50%) inset', + quoteShadow: '0px 0px 3px 0px rgb(0 0 0 / 30%) inset', + }, +} + +export default night diff --git a/utils/themes/theme_meta.ts b/utils/themes/theme_meta.ts index 299acf193..98dbbb68a 100755 --- a/utils/themes/theme_meta.ts +++ b/utils/themes/theme_meta.ts @@ -1,10 +1,10 @@ // cmd is for doraemon usage const themeMeta = { - github: { - title: 'github', - desc: 'github-like theme', - slug: 'github', + day: { + title: 'day', + desc: 'day theme', + slug: 'day', cmd: 'theme', }, }