main
ts 225 lines 8 KB
Raw
1 import type { GlobalThemeOverrides, ThemeCommonVars } from "naive-ui"
2 import { useOsTheme } from "naive-ui"
3 import tokens from "@/design-tokens.json"
4 import { Layout, RouterTransition, ThemeNameEnum } from "@/types/theme"
5 import { colorToArray, expandPattern, getThemeColors, getTypeValue } from "@/utils/theme"
6
7 type ThemeState = ReturnType<typeof getDefaultState>
8
9 interface ThemeGetters {
10 naiveCommon: ThemeCommonVars
11 }
12
13 const osTheme = useOsTheme()
14
15 export function getDefaultState() {
16 return {
17 layout: Layout.HorizontalNav, // Type of layout, with vertical or horizontal navigation
18 themeName: osTheme.value === "dark" ? ThemeNameEnum.Dark : ThemeNameEnum.Light, // Theme name (Dark, Light), with fallback to the light theme
19 routerTransition: RouterTransition.FadeUp, // Type of transition for the router
20 routerTransitionDuration: 0.3, // Duration of the router transition in seconds
21 rtl: false, // RTL (right to left) mode toggle
22 boxed: {
23 enabled: true, // Choose whether to apply a maximum width to the page
24 toolbar: true, // Choose whether to apply the maximum width to the toolbar as well
25 width: 1600 // Maximum width size in pixels
26 },
27 sidebar: {
28 autoClose: true, // Choose whether to automatically close the sidebar when the view goes below the "autoCloseBreakpoint" value
29 collapsed: false, // Indicates if the sidebar is collapsed
30 autoCloseBreakpoint: 1000, // Breakpoint for the automatic closing of the sidebar (in pixels)
31 animEase: "ease-in-out", // Type of easing for animations
32 animDuration: 0.3, // Duration of sidebar animations (in seconds)
33 openWidth: 300, // Width of the open sidebar (in pixels)
34 closeWidth: 64 // Width of the closed sidebar (in pixels)
35 },
36 footer: {
37 show: true // Show or hide the footer
38 },
39 responsive: {
40 breakpoint: 700, // Breakpoint in pixels (Desk -> Mobile)
41 // Parameters to be adjusted based on the breakpoint
42 override: {
43 viewPadding: {
44 desk: 40, // View padding for desktop
45 mobile: 20 // View padding for mobile devices
46 },
47 toolbarHeight: {
48 desk: 80, // Height of the toolbar for desktop
49 mobile: 70 // Height of the toolbar for mobile devices
50 }
51 }
52 },
53 toolbarHeight: 80, // Default toolbar height (in pixels)
54 viewPadding: 40, // Default view padding (in pixels)
55 headerBarHeight: 60, // Height of the header bar (in pixels)
56 colors: tokens.colors, // Color definitions from the token
57 borderRadius: tokens.borderRadius, // Border radius from the token
58 lineHeight: tokens.lineHeight, // Line height from the token
59 fontSize: tokens.fontSize, // Font size from the token
60 fontWeight: tokens.fontWeight, // Font weight from the token
61 fontFamily: tokens.fontFamily, // Font family from the token
62 typography: tokens.typography // Typography configurations from the token
63 }
64 }
65
66 export function getThemeOverrides(state: ThemeState): GlobalThemeOverrides {
67 const {
68 primary,
69 success,
70 warning,
71 error,
72 info,
73 background,
74 backgroundSecondary,
75 bodyBackground,
76 text,
77 textTertiary,
78 border,
79 hover
80 } = state.colors[state.themeName]
81
82 const themeColors = getThemeColors({ primary, success, warning, error, info })
83
84 const lineHeight = state.lineHeight.default
85 const borderRadius = state.borderRadius.default
86 const borderRadiusSmall = state.borderRadius.small
87 const borderColor = border
88 const hoverColor = hover
89
90 return {
91 common: {
92 ...themeColors,
93 textColorBase: text,
94 textColor1: text,
95 textColor2: text,
96 textColor3: textTertiary,
97 bodyColor: bodyBackground,
98 baseColor: background,
99 popoverColor: backgroundSecondary,
100 cardColor: background,
101 modalColor: background,
102 lineHeight,
103 borderRadius,
104 borderRadiusSmall,
105 fontSize: state.fontSize.default,
106 fontWeight: state.fontWeight.default,
107 fontWeightStrong: state.fontWeight.strong,
108 fontFamily: state.fontFamily.default,
109 fontFamilyMono: state.fontFamily.mono,
110 borderColor,
111 hoverColor,
112 dividerColor: borderColor
113 },
114 Card: {
115 color: background,
116 colorEmbedded: backgroundSecondary,
117 colorEmbeddedModal: backgroundSecondary,
118 colorEmbeddedPopover: backgroundSecondary,
119 titleFontSizeSmall: state.fontSize.cardTitle,
120 titleFontSizeMedium: state.fontSize.cardTitle,
121 titleFontSizeLarge: state.fontSize.cardTitle,
122 titleFontSizeHuge: state.fontSize.cardTitle,
123 titleFontWeight: state.fontWeight.cardTitle
124 },
125 Drawer: {
126 borderRadius: 0
127 },
128 LoadingBar: {
129 colorLoading: primary
130 },
131 Tag: {
132 colorBordered: "rgba(0, 0, 0, 0.1)"
133 },
134 Typography: {
135 headerFontSize1: getTypeValue(state, state.typography.h1.fontSize),
136 headerFontSize2: getTypeValue(state, state.typography.h2.fontSize),
137 headerFontSize3: getTypeValue(state, state.typography.h3.fontSize),
138 headerFontSize4: getTypeValue(state, state.typography.h4.fontSize),
139 headerFontSize5: getTypeValue(state, state.typography.h5.fontSize),
140 headerFontSize6: getTypeValue(state, state.typography.h6.fontSize)
141 }
142 }
143 }
144
145 export function getCssVars(state: ThemeState, getters: ThemeGetters): { [key: string]: string } {
146 const naive = getters.naiveCommon
147
148 const bgColor = naive.baseColor
149 const bgSecondaryColor = state.colors[state.themeName].backgroundSecondary
150 const fgColor = state.colors[state.themeName].text
151 const fgSecondaryColor = state.colors[state.themeName].textSecondary
152 const fgTertiaryColor = state.colors[state.themeName].textTertiary
153
154 const bgSidebar = state.colors[state.themeName].sidebarBackground
155 const bgBody = state.colors[state.themeName].bodyBackground
156
157 const boxedWidth = state.boxed.width
158 const routerTransitionDuration = state.routerTransitionDuration
159 const sidebarAnimEase = state.sidebar.animEase
160 const sidebarAnimDuration = state.sidebar.animDuration
161 const sidebarOpenWidth = state.sidebar.openWidth
162 const sidebarCloseWidth = state.sidebar.closeWidth
163 const toolbarHeight = state.toolbarHeight
164 const viewPadding = state.viewPadding
165 const headerBarHeight = state.headerBarHeight
166 const fontFamily = state.fontFamily.default
167 const fontFamilyDisplay = state.fontFamily.display
168 const fontFamilyMono = state.fontFamily.mono
169 const fontSize = state.fontSize.default
170 const lineHeight = state.lineHeight.default
171
172 const borderRadius = state.borderRadius.default
173 const borderRadiusSmall = state.borderRadius.small
174
175 const bezierEase = naive.cubicBezierEaseInOut
176
177 // This style object, imported via the themeStore, will be available application-wide and is exposed in the HTML tag as a list of CSS variables, which you can use in your CSS/SCSS code like: var(--bg-default-color)
178 const styleObject: Record<string, string> = {
179 "bg-body-color": `${bgBody}`,
180 "bg-sidebar-color": `${bgSidebar}`,
181
182 "fg-default-color": `${fgColor}`,
183 "fg-secondary-color": `${fgSecondaryColor}`,
184 "fg-tertiary-color": `${fgTertiaryColor}`,
185 "bg-default-color": `${bgColor}`,
186 "bg-secondary-color": `${bgSecondaryColor}`,
187
188 "bezier-ease": `${bezierEase}`,
189 "router-transition-duration": `${routerTransitionDuration}s`,
190 "sidebar-anim-ease": `${sidebarAnimEase}`,
191 "sidebar-anim-duration": `${sidebarAnimDuration}s`,
192 "sidebar-open-width": `${sidebarOpenWidth}px`,
193 "sidebar-close-width": `${sidebarCloseWidth}px`,
194 "boxed-width": `${boxedWidth}px`,
195 "toolbar-height": `${toolbarHeight}px`,
196 "header-bar-height": `${headerBarHeight}px`,
197 "view-padding": `${viewPadding}px`,
198 "border-radius": `${borderRadius}`,
199 "border-radius-small": `${borderRadiusSmall}`,
200
201 "font-family": `${fontFamily}`,
202 "font-family-display": `${fontFamilyDisplay}`,
203 "font-family-mono": `${fontFamilyMono}`,
204 "font-size": `${fontSize}`,
205 "line-height": `${lineHeight}`
206 }
207
208 // import colors by patterns
209 for (const pattern of ["extra(1|2|3|4)", "primary", "success", "warning", "error", "info", "border", "hover"]) {
210 const keys = expandPattern(pattern)
211
212 for (const key of keys) {
213 styleObject[`${key}-color`] = (state.colors[state.themeName] as Record<string, string>)[key] ?? ""
214 }
215 }
216
217 // add RGB values variant
218 for (const [key, value] of Object.entries(styleObject)) {
219 if (key.endsWith("-color")) {
220 styleObject[`${key}-rgb`] = colorToArray(value, "rgb").join(" ")
221 }
222 }
223
224 return styleObject
225 }