Skip to content

Commit d7ca354

Browse files
committed
feat: implement theme toggling and enhance Button styles with new color variables
1 parent 428fdfc commit d7ca354

File tree

8 files changed

+144
-132
lines changed

8 files changed

+144
-132
lines changed

apps/playground/src/App.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
<template>
2-
<RouterView></RouterView>
2+
<button @click="toggleTheme" class="fixed top-2 right-2">toggle {{ appearance }}</button>
3+
<a-theme :appearance="appearance">
4+
<RouterView />
5+
</a-theme>
36
</template>
7+
<script setup lang="ts">
8+
import { ref } from 'vue'
9+
10+
const appearance = ref('light')
11+
12+
const toggleTheme = () => {
13+
appearance.value = appearance.value === 'light' ? 'dark' : 'light'
14+
}
15+
</script>

packages/ui/src/components/button/Button.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { buttonProps, buttonEmits, ButtonSlots } from './meta'
1414
import { getCssVarColor } from '@/utils/colorAlgorithm'
1515
import { useThemeInject } from '../theme/hook'
1616
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'
17+
import { defaultColor } from '../theme/meta'
1718
1819
const props = defineProps(buttonProps)
1920
@@ -28,7 +29,7 @@ const color = computed(() => {
2829
}
2930
3031
if (props.danger) {
31-
return theme.dangerColor
32+
return 'red'
3233
}
3334
3435
return theme.primaryColor
@@ -46,7 +47,12 @@ const rootClass = computed(() => {
4647
}
4748
})
4849
const cssVars = computed(() => {
49-
return getCssVarColor(color.value)
50+
return color.value.toLowerCase() !== defaultColor.toLowerCase()
51+
? getCssVarColor(color.value, {
52+
appearance: theme.appearance,
53+
backgroundColor: theme.backgroundColor,
54+
})
55+
: {}
5056
})
5157
5258
const handleClick = (event: MouseEvent) => {

packages/ui/src/components/button/style/index.css

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,40 @@
1111
}
1212

1313
&:where(.ant-btn-solid:not(:disabled)) {
14-
@apply border-none bg-[var(--accent-color)] text-[var(--accent-color-content)];
15-
@apply hover:bg-[var(--accent-color-hover)] active:bg-[var(--accent-color-active)];
14+
@apply bg-accent text-accent-content border-none;
15+
@apply hover:bg-accent-hover active:bg-accent-active;
1616
}
1717
&:where(.ant-btn-outlined:not(:disabled)),
1818
&:where(.ant-btn-dashed:not(:disabled)) {
19-
@apply border-[var(--accent-color)] bg-transparent text-[var(--accent-color)];
20-
@apply hover:text-[var(--accent-color-hover)] active:border-[var(--accent-color-active)] active:text-[var(--accent-color-active)];
21-
@apply border-[var(--accent-color-active)] hover:border-[var(--accent-color-hover)];
19+
@apply border-accent text-accent bg-transparent;
20+
@apply hover:text-accent-hover active:border-accent-active active:text-accent-active;
21+
@apply border-accent-active hover:border-accent-hover;
2222
}
2323
&:where(.ant-btn-text:not(.ant-btn-custom-color):not(:disabled)) {
24-
@apply border-none bg-transparent text-[var(--neutral-color)];
25-
@apply hover:bg-[var(--neutral-disabled-bg)];
24+
@apply text-neutral border-none bg-transparent;
25+
@apply hover:bg-neutral-disabled-bg;
2626
}
2727
&:where(.ant-btn-text.ant-btn-custom-color:not(:disabled)) {
28-
@apply border-none bg-transparent text-[var(--accent-color)];
29-
@apply hover:bg-[var(--accent-color-1)] hover:text-[var(--accent-color-hover)];
28+
@apply text-accent border-none bg-transparent;
29+
@apply hover:bg-accent-1 hover:text-accent-hover;
3030
}
3131

3232
&:where(.ant-btn-link:not(:disabled)) {
33-
@apply border-none bg-transparent text-[var(--accent-color)] hover:text-[var(--accent-color-hover)];
33+
@apply text-accent border-none bg-transparent;
34+
@apply hover:text-accent-hover;
3435
}
3536
&:where(.ant-btn-dashed) {
3637
@apply border-dashed;
3738
}
3839
&:where(.ant-btn-filled:not(:disabled)) {
39-
@apply border-none bg-[var(--accent-color-1)] text-[var(--accent-color)] hover:text-[var(--accent-color-hover)];
40-
@apply hover:bg-[var(--accent-color-2)] active:bg-[var(--accent-color-3)] active:text-[var(--accent-color-active)];
40+
@apply text-accent bg-accent-1 border-none;
41+
@apply hover:bg-accent-2 active:bg-accent-3 active:text-accent-active;
42+
@apply hover:text-accent-hover;
4143
}
4244

4345
&:where(.ant-btn-disabled) {
4446
@apply cursor-not-allowed;
45-
@apply border-[var(--neutral-border)] bg-[var(--neutral-disabled-bg)] text-[var(--neutral-disabled)];
47+
@apply text-neutral-disabled bg-neutral-disabled-bg border-neutral-border;
4648
}
4749
&:where(.ant-btn-disabled.ant-btn-text),
4850
&:where(.ant-btn-disabled.ant-btn-link) {

packages/ui/src/components/theme/Theme.vue

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,30 @@
55
<script setup lang="ts">
66
import { themeProps } from './meta'
77
import { useThemeProvide } from './hook'
8+
import { getCssVarColor } from '@/utils/colorAlgorithm'
9+
import { watchEffect } from 'vue'
810
911
const props = defineProps(themeProps)
1012
1113
useThemeProvide(props)
14+
15+
const style = document.createElement('style')
16+
watchEffect(() => {
17+
const cssVars = getCssVarColor(props.primaryColor, {
18+
appearance: props.appearance,
19+
backgroundColor: props.backgroundColor,
20+
})
21+
document.documentElement.classList.remove('light-theme', 'dark-theme')
22+
document.documentElement.classList.add(`${props.appearance}-theme`)
23+
style.textContent = `:root.${props.appearance}-theme {
24+
${Object.entries(cssVars)
25+
.map(([key, value]) => `${key}: ${value};`)
26+
.join('\n')}
27+
}`
28+
document.head.appendChild(style)
29+
30+
return () => {
31+
document.head.removeChild(style)
32+
}
33+
})
1234
</script>
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
import { inject, InjectionKey, provide, Reactive } from 'vue'
1+
import { inject, InjectionKey, provide } from 'vue'
2+
import { ThemeProps } from './meta'
23

3-
type ThemeType = Reactive<{
4-
appearance: 'light' | 'dark'
5-
primaryColor: string
6-
dangerColor: string
7-
}>
8-
9-
const ThemeSymbol: InjectionKey<ThemeType> = Symbol('theme')
4+
const ThemeSymbol: InjectionKey<ThemeProps> = Symbol('theme')
105

116
export const useThemeInject = () => {
127
return inject(ThemeSymbol, {
138
appearance: 'light',
149
primaryColor: '#1677ff',
1510
dangerColor: '#ff4d4f',
16-
})
11+
darkBackgroundColor: '#141414',
12+
} as ThemeProps)
1713
}
1814

19-
export const useThemeProvide = (theme: ThemeType) => {
15+
export const useThemeProvide = (theme: ThemeProps) => {
2016
provide(ThemeSymbol, theme)
2117
}

packages/ui/src/components/theme/meta.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PropType, ExtractPublicPropTypes } from 'vue'
22

3+
export const defaultColor = '#1677FF'
34
// Theme Props
45
export const themeProps = {
56
/**
@@ -16,15 +17,15 @@ export const themeProps = {
1617
*/
1718
primaryColor: {
1819
type: String,
19-
default: '#1677FF',
20+
default: defaultColor,
2021
},
2122
/**
22-
* Specifies the danger color of the component
23-
* @default '#ff4d4f'
23+
* Specifies the background color of the component, only used in dark mode
24+
* @default '#141414'
2425
*/
25-
dangerColor: {
26+
backgroundColor: {
2627
type: String,
27-
default: '#ff4d4f',
28+
default: '#141414',
2829
},
2930
} as const
3031

packages/ui/src/style/base.css

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
@theme static {
2-
--color-base-100: #ffffff;
3-
--color-base-200: #f7f7f7;
4-
--color-base-300: #ededed;
5-
--color-base-content: #222222;
6-
--color-primary: #151415;
7-
--color-primary-content: #ffffff;
8-
--color-secondary: #0d58fc;
9-
--color-secondary-content: #ffffff;
10-
--color-accent: #0289ff;
2+
--color-accent-1: #e6f4ff;
3+
--color-accent-2: #bae0ff;
4+
--color-accent-3: #91caff;
5+
--color-accent-4: #69b1ff;
6+
--color-accent-5: #4096ff;
7+
--color-accent-6: #1677ff;
8+
--color-accent-7: #0958d9;
9+
--color-accent-8: #003eb3;
10+
--color-accent-9: #002c8c;
11+
--color-accent-10: #001d66;
12+
--color-accent: #1677ff;
13+
--color-accent-hover: #4096ff;
14+
--color-accent-active: #0958d9;
1115
--color-accent-content: #ffffff;
12-
--color-neutral: #666666;
13-
--color-neutral-content: #ffffff;
14-
--color-info: #0d58fc;
15-
--color-info-content: #ffffff;
16-
--color-success: #00c573;
17-
--color-success-content: #ffffff;
18-
--color-warning: #ff9900;
19-
--color-warning-content: #ffffff;
20-
--color-error: #ff3333;
21-
--color-error-content: #ffffff;
2216

23-
--neutral-color: #000000e0;
24-
--neutral-secondary: #000000a6;
25-
--neutral-disabled: #00000040;
26-
--neutral-border: #d9d9d9;
27-
--neutral-separator: #0505050f;
28-
--neutral-bg: #f5f5f5;
17+
--color-neutral: #000000e0;
18+
--color-neutral-secondary: #000000a6;
19+
--color-neutral-disabled: #00000040;
20+
--color-neutral-disabled-bg: #0000000a;
21+
--color-neutral-border: #d9d9d9;
22+
--color-neutral-separator: #0505050f;
23+
--color-neutral-bg: #f5f5f5;
24+
25+
--color-error: #ff4d4f;
26+
--color-warning: #faad14;
27+
--color-success: #52c41a;
28+
--color-info: #1677ff;
29+
}
30+
31+
.dark-theme {
32+
background-color: #141414;
2933
}
Lines changed: 45 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,41 @@
11
import { TinyColor } from '@ctrl/tinycolor'
22
import { generate, presetPalettes, presetDarkPalettes } from '@ant-design/colors'
33

4-
export const getAlphaColor = (baseColor: string, alpha: number) =>
5-
new TinyColor(baseColor).setAlpha(alpha).toRgbString()
6-
7-
export const getSolidColor = (baseColor: string, brightness: number) => {
8-
const instance = new TinyColor(baseColor)
9-
return instance.darken(brightness).toHexString()
10-
}
11-
12-
export const getTintColor = (baseColor: string, tintNumber: number) => {
13-
return new TinyColor(baseColor).tint(tintNumber).toString()
14-
}
15-
16-
export const getShadeColor = (baseColor: string, shadeNumber: number) => {
17-
return new TinyColor(baseColor).shade(shadeNumber).toString()
18-
}
19-
204
export const getLightNeutralColor = () => {
215
return {
22-
'--neutral-color': '#000000e0',
23-
'--neutral-secondary': '#000000a6',
24-
'--neutral-disabled': '#00000040',
25-
'--neutral-disabled-bg': '#0000000a',
26-
'--neutral-border': '#d9d9d9',
27-
'--neutral-separator': '#0505050f',
28-
'--neutral-bg': '#f5f5f5',
6+
'--color-neutral': '#000000e0',
7+
'--color-neutral-secondary': '#000000a6',
8+
'--color-neutral-disabled': '#00000040',
9+
'--color-neutral-disabled-bg': '#0000000a',
10+
'--color-neutral-border': '#d9d9d9',
11+
'--color-neutral-separator': '#0505050f',
12+
'--color-neutral-bg': '#f5f5f5',
2913
}
3014
}
3115

3216
export const getDarkNeutralColor = () => {
3317
return {
34-
'--neutral-color': '#FFFFFFD9',
35-
'--neutral-secondary': '#FFFFFFA6',
36-
'--neutral-disabled': '#FFFFFF40',
37-
'--neutral-disabled-bg': 'rgba(255, 255, 255, 0.08)',
38-
'--neutral-border': '#424242',
39-
'--neutral-separator': '#FDFDFD1F',
40-
'--neutral-bg': '#000000',
18+
'--color-neutral': '#FFFFFFD9',
19+
'--color-neutral-secondary': '#FFFFFFA6',
20+
'--color-neutral-disabled': '#FFFFFF40',
21+
'--color-neutral-disabled-bg': 'rgba(255, 255, 255, 0.08)',
22+
'--color-neutral-border': '#424242',
23+
'--color-neutral-separator': '#FDFDFD1F',
24+
'--color-neutral-bg': '#000000',
4125
}
4226
}
4327

28+
const cacheColors = new Map<string, Record<string, string>>()
29+
4430
export const getCssVarColor = (
4531
baseColor: string,
46-
opts?: { appearance: 'light' | 'dark'; backgroundColor: string },
32+
opts: { appearance: 'light' | 'dark'; backgroundColor: string },
4733
) => {
48-
const { appearance = 'light', backgroundColor = '#141414' } = opts || {}
34+
const { appearance = 'light', backgroundColor = '#141414' } = opts
35+
const cacheKey = `${baseColor}-${appearance}-${backgroundColor}`
36+
if (cacheColors.has(cacheKey)) {
37+
return cacheColors.get(cacheKey)
38+
}
4939
const color = new TinyColor(baseColor)
5040
const preset = appearance === 'dark' ? presetDarkPalettes : presetPalettes
5141
const colors =
@@ -55,50 +45,29 @@ export const getCssVarColor = (
5545
appearance === 'dark' ? { theme: appearance, backgroundColor } : undefined,
5646
)
5747
const accentColor = colors[5]
58-
return {
59-
'--accent-color-1': colors[0],
60-
'--accent-color-2': colors[1],
61-
'--accent-color-3': colors[2],
62-
'--accent-color-4': colors[3],
63-
'--accent-color-5': colors[4],
64-
'--accent-color-6': colors[5],
65-
'--accent-color-7': colors[6],
66-
'--accent-color-8': colors[7],
67-
'--accent-color-9': colors[8],
68-
'--accent-color-10': colors[9],
69-
'--accent-color': accentColor,
70-
'--accent-color-hover': colors[4],
71-
'--accent-color-active': colors[5],
72-
'--accent-color-content': '#ffffff',
73-
...(appearance === 'dark' ? getDarkNeutralColor() : getLightNeutralColor()),
74-
'--bg-color': baseColor,
75-
'--bg-color-hover': getTintColor(baseColor, 10),
76-
'--bg-color-active': getTintColor(baseColor, 20),
77-
'--bg-color-content': '#ffffff',
48+
const cssVars = {
49+
'--color-accent-1': colors[0],
50+
'--color-accent-2': colors[1],
51+
'--color-accent-3': colors[2],
52+
'--color-accent-4': colors[3],
53+
'--color-accent-5': colors[4],
54+
'--color-accent-6': colors[5],
55+
'--color-accent-7': colors[6],
56+
'--color-accent-8': colors[7],
57+
'--color-accent-9': colors[8],
58+
'--color-accent-10': colors[9],
59+
'--color-accent': accentColor,
60+
'--color-accent-hover': colors[4],
61+
'--color-accent-active': colors[6],
62+
'--color-accent-content': '#ffffff',
63+
64+
'--color-error': preset.red[4],
65+
'--color-warning': preset.yellow[4],
66+
'--color-success': preset.green[4],
67+
'--color-info': preset.blue[4],
7868

79-
'--border-color': baseColor,
80-
'--border-color-hover': getTintColor(baseColor, 10),
81-
'--border-color-active': getTintColor(baseColor, 20),
82-
'--border-color-tint-10': getTintColor(baseColor, 10),
83-
'--border-color-tint-20': getTintColor(baseColor, 20),
84-
'--border-color-tint-30': getTintColor(baseColor, 30),
85-
'--border-color-tint-40': getTintColor(baseColor, 40),
86-
'--border-color-tint-50': getTintColor(baseColor, 50),
87-
'--border-color-tint-60': getTintColor(baseColor, 60),
88-
'--border-color-tint-70': getTintColor(baseColor, 70),
89-
'--border-color-tint-80': getTintColor(baseColor, 80),
90-
'--border-color-tint-90': getTintColor(baseColor, 90),
91-
'--bg-color-tint-10': getTintColor(baseColor, 10),
92-
'--bg-color-tint-20': getTintColor(baseColor, 20),
93-
'--bg-color-tint-30': getTintColor(baseColor, 30),
94-
'--bg-color-tint-40': getTintColor(baseColor, 40),
95-
'--bg-color-tint-50': getTintColor(baseColor, 50),
96-
'--bg-color-tint-60': getTintColor(baseColor, 60),
97-
'--bg-color-tint-70': getTintColor(baseColor, 70),
98-
'--bg-color-tint-80': getTintColor(baseColor, 80),
99-
'--bg-color-tint-90': getTintColor(baseColor, 90),
100-
'--text-color': baseColor,
101-
'--text-color-hover': getTintColor(baseColor, 10),
102-
'--text-color-active': getTintColor(baseColor, 20),
69+
...(appearance === 'dark' ? getDarkNeutralColor() : getLightNeutralColor()),
10370
}
71+
cacheColors.set(cacheKey, cssVars)
72+
return cssVars
10473
}

0 commit comments

Comments
 (0)