feat: enhance ecommerce UI with typewriter animation, icon buttons, responsive layout, and refined design tokens

- EcommercePage.tsx: Add typewriter animation (useTypewriter hook) for slogan text with blinking cursor; replace text-based add/delete buttons with Ant Design icons (CloudUploadOutlined, DeleteOutlined); make command history panel responsive to window width (auto-collapse ≤1180px); update button labels from generic "添加" to context-specific "上传商品图" / "上传素材"
- New useTypewriter.ts hook: Character-by-character typewriter animation with configurable speed and pause-before-loop, auto-resets on text change
- reset.css: Add comprehensive HTML/body typography baseline (font-size, text-rendering, font-smoothing, line-height); extend reset coverage to select/canvas/svg elements; add overflow-wrap:anywhere for text-bearing elements; add min-width:0 to prevent form element overflow
- primitives.css: Add reusable typography utility classes (ui-page-title, ui-section-title, ui-body-copy) with design token references
- tokens.css: Expand design token set for typography scales, font weights, and leading values
- ecommerce-standalone.css: Add 689 lines of standalone ecommerce page styles
- Page CSS (ecommerce, image-workbench, more-tools, more, script-tokens, script-tokens-v5, studio-layout): Enhanced visual styles and layout refinements across all pages
- app-shell.css: Shell-level layout and styling improvements
This commit is contained in:
2026-06-11 11:31:39 +08:00
parent c367198385
commit bbea5d1e58
14 changed files with 1963 additions and 15 deletions
+48
View File
@@ -0,0 +1,48 @@
import { useState, useEffect, useRef } from "react";
/**
* 打字机动画 Hook:逐字显示文本,完成后停顿指定时间再重复。
*
* @param text 要显示的文本
* @param typingSpeed 每个字的间隔(ms),默认 120
* @param pauseDuration 打完后的停顿时间(ms),默认 5000
* @returns 当前已显示的文字
*/
export function useTypewriter(text: string, typingSpeed = 120, pauseDuration = 5000) {
const [displayText, setDisplayText] = useState("");
const indexRef = useRef(0);
const pausingRef = useRef(false);
const restartTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
// 重置所有状态
indexRef.current = 0;
pausingRef.current = false;
setDisplayText("");
if (restartTimerRef.current) clearTimeout(restartTimerRef.current);
const interval = setInterval(() => {
if (pausingRef.current) return;
if (indexRef.current < text.length) {
indexRef.current++;
setDisplayText(text.slice(0, indexRef.current));
} else {
// 打字完成,进入停顿
pausingRef.current = true;
restartTimerRef.current = setTimeout(() => {
indexRef.current = 0;
pausingRef.current = false;
setDisplayText("");
}, pauseDuration);
}
}, typingSpeed);
return () => {
clearInterval(interval);
if (restartTimerRef.current) clearTimeout(restartTimerRef.current);
};
}, [text, typingSpeed, pauseDuration]);
return displayText;
}