Skip to content

Commit

Permalink
Merge pull request #19 from cszo/dev
Browse files Browse the repository at this point in the history
feat: change theme color
  • Loading branch information
cszo committed Jul 31, 2023
2 parents fa683c1 + 0a5b7f4 commit be2625b
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 6 deletions.
19 changes: 18 additions & 1 deletion src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import { RouterProvider, createBrowserRouter, createHashRouter } from 'react-router-dom'
import { routes } from './routes'

import { ConfigProvider } from 'antd'
import { useAppSelector } from './store'
import { themeColor } from '@/features/theme/themeSlice'

export default function App() {
const createdRoutes =
import.meta.env.VITE_ROUTER_HISTORY === 'hash'
? createHashRouter(routes)
: createBrowserRouter(routes)
return <RouterProvider router={createdRoutes} />

const primaryColor = useAppSelector(themeColor)

return (
<ConfigProvider
theme={{
token: {
colorPrimary: primaryColor
}
}}
>
<RouterProvider router={createdRoutes} />
</ConfigProvider>
)
}
14 changes: 14 additions & 0 deletions src/features/theme/theme.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.skin {
position: relative;
width: 32px;
height: 32px;
}

.skin-input {
width: 32px;
position: absolute;
left: 0;
z-index: 1;
opacity: 0;
cursor: pointer;
}
31 changes: 31 additions & 0 deletions src/features/theme/theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ChangeEvent } from 'react'
import { Button, Input } from 'antd'
import { SkinOutlined } from '@ant-design/icons'

import { useAppSelector, useAppDispatch } from '@/store'
import { setColor, themeColor } from './themeSlice'

import { debounce } from '@/utils/functions'

import styles from './theme.module.css'

export default function Theme() {
const primaryColor = useAppSelector(themeColor)
const dispatch = useAppDispatch()

const changeMainColor = (e: ChangeEvent<HTMLInputElement>) => {
dispatch(setColor(e.target.value))
}

return (
<div className={styles.skin}>
<Button type="primary" shape="circle" icon={<SkinOutlined />} />
<Input
type="color"
className={styles.skinInput}
defaultValue={primaryColor}
onChange={debounce(changeMainColor, 500)}
></Input>
</div>
)
}
28 changes: 28 additions & 0 deletions src/features/theme/themeSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '@/store'

export interface ThemeState {
themeColor: string
}

// use redux-persist?https://github.com/rt2zz/redux-persist
const initialState: ThemeState = JSON.parse(
localStorage.getItem('theme') || '{"themeColor":"#247fff"}'
)

export const themeSlice = createSlice({
name: 'theme',
initialState,
reducers: {
setColor: (state, action: PayloadAction<string>) => {
state.themeColor = action.payload
localStorage.setItem('theme', JSON.stringify({ themeColor: action.payload }))
}
}
})

export const { setColor } = themeSlice.actions

export const themeColor = (state: RootState) => state.theme.themeColor

export default themeSlice.reducer
10 changes: 6 additions & 4 deletions src/layouts/header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Breadcrumb, Row, Button, Dropdown, MenuProps } from 'antd'
import { Breadcrumb, Row, Space, Button, Dropdown, MenuProps } from 'antd'
import { Link, useLocation, useNavigate, Navigate, useLoaderData } from 'react-router-dom'
import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'

import Theme from '@/features/theme/theme'

import { breadcrumbNameMap } from '../routes'
import { logout } from '../routes/auth'

export default function AdminLayout() {
const userInfo: any = useLoaderData()
console.log('userInfo', userInfo)

const location = useLocation()
const navigate = useNavigate()
Expand Down Expand Up @@ -73,7 +74,8 @@ export default function AdminLayout() {
<Row align="middle">
<Breadcrumb items={breadcrumbItems} />
</Row>
<Row align="middle" style={{ paddingRight: 16 }}>
<Space size={12}>
<Theme />
<Dropdown menu={{ items }} placement="bottom">
<Row align="middle">
<img
Expand All @@ -83,7 +85,7 @@ export default function AdminLayout() {
<span style={{ marginLeft: 8, color: 'gray' }}>{userInfo?.user?.username}</span>
</Row>
</Dropdown>
</Row>
</Space>
</Row>
)
}
4 changes: 3 additions & 1 deletion src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'

import counterReducer from './features/counter/counterSlice'
import themeReducer from './features/theme/themeSlice'

export const store = configureStore({
reducer: {
counter: counterReducer
counter: counterReducer,
theme: themeReducer
}
})

Expand Down
12 changes: 12 additions & 0 deletions src/utils/functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): T {
let timer: ReturnType<typeof setTimeout> | null = null
return function (this: any, ...args: Parameters<T>) {
if (timer !== null) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
} as T
}

0 comments on commit be2625b

Please sign in to comment.