main
ts 263 lines 9.88 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.d"
5 import { colorToArray, colorToHslValues, 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.VerticalNav, // 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: background,
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 titleFontSizeSmall: state.fontSize.cardTitle,
119 titleFontSizeMedium: state.fontSize.cardTitle,
120 titleFontSizeLarge: state.fontSize.cardTitle,
121 titleFontSizeHuge: state.fontSize.cardTitle,
122 titleFontWeight: state.fontWeight.cardTitle
123 },
124 Form: {
125 feedbackPadding: "4px 2px 8px",
126 feedbackFontSizeSmall: "10px",
127 feedbackFontSizeMedium: "12px",
128 feedbackFontSizeLarge: "14px"
129 },
130 LoadingBar: {
131 colorLoading: primary
132 },
133 Modal: {
134 peers: {
135 Card: {
136 color: background,
137 colorEmbedded: backgroundSecondary
138 }
139 }
140 },
141 Tag: {
142 colorBordered: "rgba(0, 0, 0, 0.1)"
143 },
144 Typography: {
145 headerFontSize1: getTypeValue(state, state.typography.h1.fontSize),
146 headerFontSize2: getTypeValue(state, state.typography.h2.fontSize),
147 headerFontSize3: getTypeValue(state, state.typography.h3.fontSize),
148 headerFontSize4: getTypeValue(state, state.typography.h4.fontSize),
149 headerFontSize5: getTypeValue(state, state.typography.h5.fontSize),
150 headerFontSize6: getTypeValue(state, state.typography.h6.fontSize)
151 }
152 }
153 }
154
155 export function getCssVars(state: ThemeState, getters: ThemeGetters): { [key: string]: string } {
156 const naive = getters.naiveCommon
157
158 const bgColor = naive.baseColor
159 const bgSecondaryColor = state.colors[state.themeName].backgroundSecondary
160 const fgColor = state.colors[state.themeName].text
161 const fgSecondaryColor = state.colors[state.themeName].textSecondary
162 const fgTertiaryColor = state.colors[state.themeName].textTertiary
163
164 const bgSidebar = state.colors[state.themeName].sidebarBackground
165 const bgBody = state.colors[state.themeName].bodyBackground
166
167 const boxedWidth = state.boxed.width
168 const routerTransitionDuration = state.routerTransitionDuration
169 const sidebarAnimEase = state.sidebar.animEase
170 const sidebarAnimDuration = state.sidebar.animDuration
171 const sidebarOpenWidth = state.sidebar.openWidth
172 const sidebarCloseWidth = state.sidebar.closeWidth
173 const toolbarHeight = state.toolbarHeight
174 const viewPadding = state.viewPadding
175 const headerBarHeight = state.headerBarHeight
176 const fontFamily = state.fontFamily.default
177 const fontFamilyDisplay = state.fontFamily.display
178 const fontFamilyMono = state.fontFamily.mono
179 const fontSize = state.fontSize.default
180 const lineHeight = state.lineHeight.default
181
182 const borderRadius = state.borderRadius.default
183 const borderRadiusSmall = state.borderRadius.small
184
185 const bezierEase = naive.cubicBezierEaseInOut
186
187 // 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)
188 const styleObject: Record<string, string> = {
189 "bg-body-color": `${bgBody}`,
190 "bg-sidebar-color": `${bgSidebar}`,
191
192 "fg-default-color": `${fgColor}`,
193 "fg-secondary-color": `${fgSecondaryColor}`,
194 "fg-tertiary-color": `${fgTertiaryColor}`,
195 "bg-default-color": `${bgColor}`,
196 "bg-secondary-color": `${bgSecondaryColor}`,
197
198 "bezier-ease": `${bezierEase}`,
199 "router-transition-duration": `${routerTransitionDuration}s`,
200 "sidebar-anim-ease": `${sidebarAnimEase}`,
201 "sidebar-anim-duration": `${sidebarAnimDuration}s`,
202 "sidebar-open-width": `${sidebarOpenWidth}px`,
203 "sidebar-close-width": `${sidebarCloseWidth}px`,
204 "boxed-width": `${boxedWidth}px`,
205 "toolbar-height": `${toolbarHeight}px`,
206 "header-bar-height": `${headerBarHeight}px`,
207 "view-padding": `${viewPadding}px`,
208 "border-radius": `${borderRadius}`,
209 "border-radius-small": `${borderRadiusSmall}`,
210
211 "font-family": `${fontFamily}`,
212 "font-family-display": `${fontFamilyDisplay}`,
213 "font-family-mono": `${fontFamilyMono}`,
214 "font-size": `${fontSize}`,
215 "line-height": `${lineHeight}`,
216
217 background: `${colorToHslValues(bgSecondaryColor)}`,
218 "background-elevated": `${colorToHslValues(bgColor)}`,
219 "background-surface": `${colorToHslValues(bgSecondaryColor)}`,
220 foreground: `${colorToHslValues(fgColor)}`,
221 card: `${colorToHslValues(bgColor)}`,
222 "card-foreground": `${colorToHslValues(fgColor)}`,
223 popover: `${colorToHslValues(bgColor)}`,
224 "popover-foreground": `${colorToHslValues(fgColor)}`,
225 primary: `${colorToHslValues(state.colors[state.themeName].primary)}`,
226 "primary-foreground": `${colorToHslValues(bgBody)}`,
227 secondary: `${colorToHslValues(state.colors[state.themeName].primary)}`,
228 "secondary-foreground": `${colorToHslValues(fgSecondaryColor)}`,
229 muted: `${colorToHslValues(bgSecondaryColor)}`,
230 "muted-foreground": `${colorToHslValues(fgSecondaryColor)}`,
231 accent: `${colorToHslValues(state.colors[state.themeName].primary)}`,
232 "accent-foreground": `${colorToHslValues(bgBody)}`,
233 destructive: `${colorToHslValues(state.colors[state.themeName].error)}`,
234 "destructive-foreground": `${colorToHslValues(bgBody)}`,
235 border: `${colorToHslValues(state.colors[state.themeName].border)}`,
236 input: `${colorToHslValues(bgSecondaryColor)}`,
237 ring: `${colorToHslValues(state.colors[state.themeName].border)}`,
238 "severity-info": `${colorToHslValues(state.colors[state.themeName].info)}`,
239 "severity-low": `${colorToHslValues(state.colors[state.themeName].success)}`,
240 "severity-medium": `${colorToHslValues(state.colors[state.themeName].warning)}`,
241 "severity-high": `${colorToHslValues(state.colors[state.themeName].error)}`,
242 "severity-critical": `${colorToHslValues(state.colors[state.themeName].error)}`,
243 "infra-email": `${colorToHslValues(state.colors[state.themeName].info)}`
244 }
245
246 // import colors by patterns
247 for (const pattern of ["extra(1|2|3|4)", "primary", "success", "warning", "error", "info", "border", "hover"]) {
248 const keys = expandPattern(pattern)
249
250 for (const key of keys) {
251 styleObject[`${key}-color`] = (state.colors[state.themeName] as Record<string, string>)[key] ?? ""
252 }
253 }
254
255 // add RGB values variant
256 for (const [key, value] of Object.entries(styleObject)) {
257 if (key.endsWith("-color")) {
258 styleObject[`${key}-rgb`] = colorToArray(value, "rgb").join(" ")
259 }
260 }
261
262 return styleObject
263 }