Skip to content

Commit 8c44116

Browse files
author
cole
committed
feat: custom theme
1 parent 0fd49f3 commit 8c44116

File tree

7 files changed

+325
-46
lines changed

7 files changed

+325
-46
lines changed

src/App.jsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ export default defineComponent({
88
inheritAttrs: false,
99
setup () {
1010
const localeMessage = ref({})
11-
const customTheme = ref({})
1211

13-
function setCustomTheme (value) {
14-
customTheme.value = value
12+
const theme = ref('dark')
13+
const themeProvider = ref({})
14+
15+
function setConfigTheme (name, value) {
16+
theme.value = name
17+
themeProvider.value = value
1518
}
1619

1720
function setLocaleMessage (value) {
@@ -23,7 +26,8 @@ export default defineComponent({
2326
}
2427

2528
createAppInstance({
26-
setCustomTheme: setCustomTheme,
29+
theme: theme,
30+
setConfigTheme: setConfigTheme,
2731
setLocaleMessage: setLocaleMessage,
2832
onAvatarAction: onAvatarAction
2933
})
@@ -32,7 +36,7 @@ export default defineComponent({
3236
const { antd, packages } = unref(localeMessage)
3337

3438
return (
35-
<ConfigProvider locale={antd} theme={unref(customTheme)}>
39+
<ConfigProvider locale={antd} theme={unref(themeProvider)}>
3640
<LocaleProvider locale={packages}>
3741
<RouterView/>
3842
</LocaleProvider>

src/layout/compatible/navbar/index.jsx

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { defineComponent } from 'vue'
1+
import { defineComponent, ref, unref } from 'vue'
2+
import { ConfigProvider } from 'ant-design-vue'
23
import Breadcrumb from '../../components/breadcrumb'
34
import Settings from '../../components/settings'
45
import Fullscreen from '../../components/fullscreen'
@@ -29,10 +30,17 @@ export default defineComponent({
2930
const { prefixCls } = useConfigInject('pro-layout-navbar', props)
3031
const [wrapSSR, hashId] = useStyle(prefixCls)
3132

33+
const popupContainer = ref(null)
34+
3235
function onCollapse () {
3336
emit('collapse', !props.collapsed)
3437
}
3538

39+
function getPopupContainer () {
40+
const plain = unref(popupContainer)
41+
return plain ? (plain.$el || plain) : plain
42+
}
43+
3644
return () => {
3745
const { router, collapsed } = props
3846

@@ -42,18 +50,24 @@ export default defineComponent({
4250

4351
return wrapSSR(
4452
<div class={[prefixCls.value, hashId.value]} {...attrs}>
45-
<div class={`${prefixCls.value}-left`}>
46-
<div class={`${prefixCls.value}-collapse`} onClick={onCollapse}>
47-
<HamburgerOutlined class={collapseClass}/>
53+
<ConfigProvider getPopupContainer={getPopupContainer}>
54+
<div class={`${prefixCls.value}-popup-container`} ref={popupContainer}>
55+
<div class={`${prefixCls.value}-content`}>
56+
<div class={`${prefixCls.value}-left`}>
57+
<div class={`${prefixCls.value}-collapse`} onClick={onCollapse}>
58+
<HamburgerOutlined class={collapseClass}/>
59+
</div>
60+
<Breadcrumb router={router}/>
61+
</div>
62+
<div class={`${prefixCls.value}-right`}>
63+
<Settings/>
64+
<Fullscreen/>
65+
<Language/>
66+
<Avatar/>
67+
</div>
68+
</div>
4869
</div>
49-
<Breadcrumb router={router}/>
50-
</div>
51-
<div class={`${prefixCls.value}-right`}>
52-
<Settings/>
53-
<Fullscreen/>
54-
<Language/>
55-
<Avatar/>
56-
</div>
70+
</ConfigProvider>
5771
</div>
5872
)
5973
}

src/layout/compatible/navbar/style/index.js

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,41 @@ function genBaseStyle (token) {
44
const { componentCls, navbarHeight, navbarPaddingInline, navbarCollapseSize } = token
55
return {
66
[componentCls]: {
7-
height: navbarHeight,
8-
display: 'flex',
9-
justifyContent: 'space-between',
10-
paddingInline: navbarPaddingInline,
11-
background: token.colorBgContainer,
7+
position: 'relative',
128
userSelect: 'none',
13-
[`${componentCls}-left, ${componentCls}-right`]: {
9+
[`${componentCls}-popup-container`]: {
10+
position: 'relative'
11+
},
12+
[`${componentCls}-content`]: {
1413
height: navbarHeight,
1514
display: 'flex',
16-
alignItems: 'center'
17-
},
18-
[`${componentCls}-collapse`]: {
19-
width: navbarCollapseSize,
20-
height: navbarCollapseSize,
21-
fontSize: navbarCollapseSize,
22-
lineHeight: `${navbarCollapseSize}px`,
23-
color: token.colorText,
24-
textAlign: 'center',
25-
cursor: 'pointer',
26-
[`&:hover`]: {
27-
color: token.colorPrimaryHover
28-
},
29-
[`&:active`]: {
30-
color: token.colorPrimaryActive
15+
justifyContent: 'space-between',
16+
paddingInline: navbarPaddingInline,
17+
background: token.colorBgContainer,
18+
[`${componentCls}-left, ${componentCls}-right`]: {
19+
height: navbarHeight,
20+
display: 'flex',
21+
alignItems: 'center'
3122
},
32-
[`${componentCls}-collapse-icon`]: {
33-
transition: 'all 0.3s cubic-bezier(0.2, 0, 0, 1) 0s',
34-
[`&__down`]: {
35-
transform: 'rotate(90deg)'
23+
[`${componentCls}-collapse`]: {
24+
width: navbarCollapseSize,
25+
height: navbarCollapseSize,
26+
fontSize: navbarCollapseSize,
27+
lineHeight: `${navbarCollapseSize}px`,
28+
color: token.colorText,
29+
textAlign: 'center',
30+
cursor: 'pointer',
31+
[`&:hover`]: {
32+
color: token.colorPrimaryHover
33+
},
34+
[`&:active`]: {
35+
color: token.colorPrimaryActive
36+
},
37+
[`${componentCls}-collapse-icon`]: {
38+
transition: 'all 0.3s cubic-bezier(0.2, 0, 0, 1) 0s',
39+
[`&__down`]: {
40+
transform: 'rotate(90deg)'
41+
}
3642
}
3743
}
3844
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { defineComponent, ref, unref, watch } from 'vue'
2+
import { Switch, theme as antTheme, Tooltip } from 'ant-design-vue'
3+
import { CheckOutlined } from '@ant-design/icons-vue'
4+
import { useConfigInject } from '@utils/extend'
5+
import useStyle from './style/theme-settings'
6+
import { useAppInstance } from '@/useAppInstance'
7+
8+
const themeList = [
9+
{
10+
name: 'light',
11+
title: '亮色主题'
12+
},
13+
{
14+
name: 'dark',
15+
title: '暗色主题'
16+
},
17+
{
18+
name: 'real-dark',
19+
title: '暗黑模式'
20+
}
21+
]
22+
23+
const primaryList = [
24+
{
25+
name: 'blue',
26+
title: '拂晓蓝'
27+
},
28+
{
29+
name: 'red',
30+
title: '薄暮'
31+
},
32+
{
33+
name: 'volcano',
34+
title: '火山'
35+
},
36+
{
37+
name: 'gold',
38+
title: '日暮'
39+
},
40+
{
41+
name: 'cyan',
42+
title: '明青'
43+
},
44+
{
45+
name: 'green',
46+
title: '极光绿'
47+
},
48+
{
49+
name: 'geekblue',
50+
title: '极客蓝'
51+
},
52+
{
53+
name: 'purple',
54+
title: '酱紫'
55+
}
56+
]
57+
58+
export default defineComponent({
59+
inheritAttrs: false,
60+
setup (props, { attrs }) {
61+
const { prefixCls } = useConfigInject('pro-theme-settings', props)
62+
const [wrapSSR, hashId] = useStyle(prefixCls)
63+
const { token } = antTheme.useToken()
64+
const { darkAlgorithm, compactAlgorithm } = antTheme
65+
66+
const { setConfigTheme } = useAppInstance()
67+
68+
const theme = ref('dark')
69+
const primary = ref('blue')
70+
const compact = ref(false)
71+
72+
watch([theme, primary, compact], ([themeValue, primaryValue, compactValue]) => {
73+
const algorithm = [
74+
themeValue === 'real-dark' ? darkAlgorithm : null,
75+
compactValue ? compactAlgorithm : null
76+
]
77+
setConfigTheme && setConfigTheme(themeValue, {
78+
algorithm: algorithm.filter((value) => !!value),
79+
token: { colorPrimary: unref(token)[primaryValue] }
80+
})
81+
})
82+
83+
function onThemeClick (value) {
84+
theme.value = value
85+
}
86+
87+
function onPrimaryClick (value) {
88+
primary.value = value
89+
}
90+
91+
return () => {
92+
const themeDom = themeList.map((item) => {
93+
return (
94+
<Tooltip title={item.title}>
95+
<div
96+
class={[`${prefixCls.value}-theme`, `${prefixCls.value}-theme-${item.name}`]}
97+
onClick={onThemeClick.bind(null, item.name)}
98+
>
99+
{unref(theme) === item.name ? <CheckOutlined/> : null}
100+
</div>
101+
</Tooltip>
102+
)
103+
})
104+
105+
const primaryDom = primaryList.map((item) => {
106+
const primaryStyle = { backgroundColor: unref(token)[item.name] }
107+
return (
108+
<Tooltip title={item.title}>
109+
<div
110+
class={`${prefixCls.value}-primary`}
111+
style={primaryStyle}
112+
onClick={onPrimaryClick.bind(null, item.name)}
113+
>
114+
{unref(primary) === item.name ? <CheckOutlined/> : null}
115+
</div>
116+
</Tooltip>
117+
)
118+
})
119+
120+
return wrapSSR(
121+
<div class={[prefixCls.value, hashId.value]} {...attrs}>
122+
<div class={`${prefixCls.value}-block-wrap`}>
123+
<div class={`${prefixCls.value}-title`}>整体风格</div>
124+
<div class={`${prefixCls.value}-theme-block`}>
125+
{themeDom}
126+
</div>
127+
</div>
128+
<div class={`${prefixCls.value}-block-wrap`}>
129+
<div class={`${prefixCls.value}-title`}>主题色</div>
130+
<div class={`${prefixCls.value}-primary-block`}>
131+
{primaryDom}
132+
</div>
133+
</div>
134+
<div class={`${prefixCls.value}-block-wrap`}>
135+
<div class={`${prefixCls.value}-title`}>紧凑主题</div>
136+
<div class={`${prefixCls.value}-compact-block`}>
137+
<Switch v-model:checked={compact.value}/>
138+
</div>
139+
</div>
140+
</div>
141+
)
142+
}
143+
}
144+
})

src/layout/components/settings/index.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { defineComponent, ref, unref } from 'vue'
22
import { Drawer } from 'ant-design-vue'
33
import { SettingOutlined } from '@ant-design/icons-vue'
4+
import ThemeSettings from './ThemeSettings'
45
import { useConfigInject } from '@utils/extend'
56
import useStyle from './style'
67

@@ -24,19 +25,19 @@ export default defineComponent({
2425

2526
return () => {
2627
const drawerProps = {
28+
width: 320,
2729
open: unref(open),
2830
onClose: onDrawerClose,
2931
getContainer: () => unref(popupContainer)
3032
}
31-
3233
return wrapSSR(
3334
<div class={[prefixCls.value, hashId.value]} {...attrs}>
3435
<div class={`${prefixCls.value}-popup-container`} ref={popupContainer}>
3536
<div class={`${prefixCls.value}-content`} onClick={onDrawerOpen}>
3637
<SettingOutlined/>
3738
</div>
3839
<Drawer {...drawerProps}>
39-
自定义主题
40+
<ThemeSettings/>
4041
</Drawer>
4142
</div>
4243
</div>

0 commit comments

Comments
 (0)