Skip to content

Commit 0473a6b

Browse files
committed
feat(admin/core/theme): 添加 Theme.transitionDuration 方法用于获取 CSS 中的动画过渡时长
1 parent 1e9a930 commit 0473a6b

9 files changed

Lines changed: 262 additions & 181 deletions

File tree

admin/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,19 @@
100100
"bowser": "^2.11.0",
101101
"echarts": "^5.6.0",
102102
"intl-messageformat": "^10.7.15",
103-
"material-symbols": "^0.29.0",
103+
"material-symbols": "^0.29.1",
104104
"printd": "^1.6.0",
105105
"qr-code-styling": "^1.9.1",
106106
"quill": "^2.0.3",
107107
"solid-js": "^1.9.5",
108108
"solid-transition-group": "^0.3.0",
109-
"tailwindcss": "^4.0.12",
109+
"tailwindcss": "^4.0.14",
110110
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
111111
"yaml": "^2.7.0"
112112
},
113113
"devDependencies": {
114114
"@solidjs/testing-library": "^0.8.10",
115-
"@tailwindcss/vite": "^4.0.12",
115+
"@tailwindcss/vite": "^4.0.14",
116116
"@testing-library/jest-dom": "^6.6.3",
117117
"@testing-library/user-event": "^14.6.1",
118118
"@types/node": "^22.13.10",

admin/src/components/tree/list/list.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Divider } from '@/components/divider';
1010
import { Icon } from '@/components/icon';
1111
import type { Props as ContainerProps } from '@/components/tree/container';
1212
import { findItems, type Item } from '@/components/tree/item';
13+
import { sleep, Theme } from '@/core';
1314

1415
export interface Props extends ContainerProps {
1516
/**
@@ -48,13 +49,22 @@ export function List(props: Props): JSX.Element {
4849
let oldValue: string|undefined = undefined;
4950
const [selected, setSelected] = createSignal<string|undefined>(props.selected ?? (props.anchor ? useLocation().pathname : undefined));
5051
const [selectedIndexes, setSelectedIndexes] = createSignal(findItems(props.children, selected()));// 选中项在每一层中的索引
52+
const [ref, setRef] = createSignal<HTMLElement>(); // 记录最终选中项
5153

5254
createEffect(() => {
5355
oldValue = untrack(selected);
5456
setSelected(props.selected);
5557
setSelectedIndexes(findItems(props.children, props.selected));
5658
});
5759

60+
createEffect(() => {
61+
if (ref()) {
62+
sleep(Theme.transitionDuration(300)).then(() => { // 等待动画完成,再滚动。否则先滚动到指定位置,再展开,将显示错位。
63+
ref()!.scrollIntoView({ block: 'center' });
64+
});
65+
}
66+
});
67+
5868
const All = (p: { items: Array<Item>, indent: number, selectedIndex: number }): JSX.Element => {
5969
return <For each={p.items}>
6070
{(item, index) => {
@@ -96,7 +106,7 @@ export function List(props: Props): JSX.Element {
96106
setOpen(p.isSelected);
97107

98108
if (p.isSelected && ref) {
99-
ref.scrollIntoView({ block: 'center' });
109+
setRef(ref);
100110
}
101111
});
102112

admin/src/core/theme/contrast.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function getContrast(conf: Config, preset: Contrast) {
2020
if (!c) {
2121
c = preset;
2222
} else if (contrasts.indexOf(c) < 0) {
23-
console.warn(`从 localStorage 读取的 ${key}${c} 不符合要求!`);
23+
console.warn(`从 conf 读取的 ${key}${c} 不符合要求!`);
2424
c = 'nopreference';
2525
}
2626
return c;

admin/src/core/theme/scheme.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2024 caixw
1+
// SPDX-FileCopyrightText: 2024-2025 caixw
22
//
33
// SPDX-License-Identifier: MIT
44

@@ -66,8 +66,8 @@ export function genScheme(primary: number, error?: number, step = 60): Scheme {
6666

6767
export function genSchemes(primary: number, size = 16, step = 60): Array<Scheme> {
6868
const schemes: Array<Scheme> = [];
69-
for(let i =0;i<size;i++) {
70-
schemes.push(genScheme(primary+i*48, undefined, step));
69+
for (let i = 0; i < size; i++) {
70+
schemes.push(genScheme(primary + i * 48, undefined, step));
7171
}
7272
return schemes;
73-
}
73+
}

admin/src/core/theme/theme.spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-FileCopyrightText: 2025 caixw
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
import { describe, expect, test } from 'vitest';
6+
7+
import { Config } from '@/core/config';
8+
import { Theme } from './theme';
9+
import './theme.css';
10+
11+
describe('Theme', () => {
12+
Theme.init(new Config('id'), Theme.genScheme(10));
13+
14+
test('transitionDuration', () => {
15+
expect(Theme.transitionDuration(100)).toEqual(100);
16+
17+
document.documentElement.style.setProperty('--transition-duration', '300ms');
18+
expect(Theme.transitionDuration(100)).toEqual(300);
19+
20+
document.documentElement.style.setProperty('--transition-duration', '300s');
21+
expect(Theme.transitionDuration(100)).toEqual(300 * 1000);
22+
23+
document.documentElement.style.setProperty('--transition-duration', '300');
24+
expect(Theme.transitionDuration(100)).toEqual(300);
25+
});
26+
27+
test('mode', () => {
28+
Theme.setMode('dark');
29+
expect(Theme.mode()).toEqual('dark');
30+
31+
Theme.setMode('system');
32+
expect(Theme.mode()).toEqual('system');
33+
34+
Theme.setMode('light');
35+
expect(Theme.mode()).toEqual('light');
36+
});
37+
38+
test('contrast', () => {
39+
Theme.setContrast('less');
40+
expect(Theme.contrast()).toEqual('less');
41+
42+
Theme.setContrast('more');
43+
expect(Theme.contrast()).toEqual('more');
44+
});
45+
46+
test('scheme', () => {
47+
Theme.setScheme(Theme.genScheme(10));
48+
expect(Theme.scheme().primary).toEqual(10);
49+
50+
Theme.setScheme(Theme.genScheme(100));
51+
expect(Theme.scheme().primary).toEqual(100);
52+
});
53+
});

admin/src/core/theme/theme.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,27 @@ export class Theme {
3636
Theme.switchConfig(conf);
3737
}
3838

39+
/**
40+
* 获取动画的过滤时间,即 CSS 的 --transition-duration 变量的值。
41+
*
42+
* @param preset 默认值,找不到时返回该值,单位为毫秒;
43+
* @param 返回以毫秒为单位的数值;
44+
*/
45+
static transitionDuration(preset: number): number {
46+
let val = getComputedStyle(document.documentElement).getPropertyValue('--transition-duration');
47+
if (!val) {
48+
return preset;
49+
}
50+
51+
if (val.endsWith('ms')) {
52+
return parseInt(val.substring(0, val.length - 2));
53+
} else if (val.endsWith('s')) {
54+
return parseInt(val.substring(0, val.length - 1))*1000;
55+
} else { // 其它直接当作数值处理
56+
return parseInt(val);
57+
}
58+
}
59+
3960
/**
4061
* 切换配置
4162
*/

cmd/admin/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"dependencies": {
2424
"@cmfx/admin": "0.8.12",
2525
"@solidjs/router": "^0.15.3",
26-
"tailwindcss": "^4.0.12",
26+
"tailwindcss": "^4.0.14",
2727
"solid-js": "^1.9.5"
2828
},
2929
"devDependencies": {
@@ -33,7 +33,7 @@
3333
"cssnano": "^7.0.6",
3434
"postcss": "^8.5.3",
3535
"solid-devtools": "^0.33.0",
36-
"@tailwindcss/vite": "^4.0.12",
36+
"@tailwindcss/vite": "^4.0.14",
3737
"typescript": "^5.8.2",
3838
"vite": "^6.2.1",
3939
"vite-plugin-solid": "^2.11.6"

0 commit comments

Comments
 (0)