feat(web): 重做设计系统与全部页面,前端观感对齐当下审美
用户反馈"UI 太丑、太简陋"。不是换配色,而是先立 token 再让页面去用: - tailwind.config.js:纸白 paper / 墨绿 primary / 陶土橙 clay + 语义色 sage/wheat/rust/sky,字号阶、圆角阶、投影、动效 - index.css:卡片、按钮五种变体、输入、pill/chip、导航、骨架屏 - 新增 icons.tsx(线性图标集)与 ui.tsx(Button/Sheet/Toast/空态/骨架/PageHeader) - 新增 AppShell 取代 Layout + WorkspaceNav:桌面侧栏 + 移动顶部横条,工单未读角标 - 六个页面全部重写:登录、首页、任务、看板、工单、知识、成员、邀请落地 - 详情抽屉改用 Sheet,工单态补齐需求人/办理人/退回次数/动作按钮 e2e 因 DOM 升级同步调整(抽屉按 role=dialog 定位、下拉改用 aria-label), 三套用例(7 + 8 + 7 项)全部重跑通过;tsc 0 错,构建 45 modules / gzip 76.70 kB。
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
import type { SVGProps } from "react";
|
||||
|
||||
type IconProps = SVGProps<SVGSVGElement> & { size?: number };
|
||||
|
||||
function base({ size = 16, ...rest }: IconProps) {
|
||||
return {
|
||||
width: size,
|
||||
height: size,
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
strokeWidth: 1.7,
|
||||
strokeLinecap: "round" as const,
|
||||
strokeLinejoin: "round" as const,
|
||||
"aria-hidden": true,
|
||||
...rest,
|
||||
};
|
||||
}
|
||||
|
||||
export const Check = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const CheckCircle = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="m8.5 12 2.5 2.5 4.5-5" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Circle = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<circle cx="12" cy="12" r="8.5" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Search = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<circle cx="11" cy="11" r="6.5" />
|
||||
<path d="m16 16 4 4" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Plus = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const X = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M18 6 6 18M6 6l12 12" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ChevronDown = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="m6 9 6 6 6-6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ChevronRight = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="m9 6 6 6-6 6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ChevronLeft = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="m15 6-6 6 6 6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ArrowRight = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M5 12h14M13 6l6 6-6 6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Columns = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<rect x="3.5" y="4" width="17" height="16" rx="2.5" />
|
||||
<path d="M9.5 4v16M15 4v16" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const TicketIcon = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M3.5 9.5V7a2 2 0 0 1 2-2h13a2 2 0 0 1 2 2v2.5a2.5 2.5 0 0 0 0 5V17a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-2.5a2.5 2.5 0 0 0 0-5Z" />
|
||||
<path d="M12 7v2M12 15v2" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Book = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M4 5.5A2.5 2.5 0 0 1 6.5 3H19v15.5H6.5A2.5 2.5 0 0 0 4 21Z" />
|
||||
<path d="M4 18.5V5.5M8.5 7.5h6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Users = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<circle cx="9" cy="8.5" r="3.2" />
|
||||
<path d="M3.5 19.5a5.5 5.5 0 0 1 11 0" />
|
||||
<path d="M16 6.2a3.2 3.2 0 0 1 0 6M17.5 15.2a5.5 5.5 0 0 1 3 4.3" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Inbox = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M3.5 13.5h4l1.2 2.2h6.6l1.2-2.2h4" />
|
||||
<path d="M5.6 4.5h12.8l2.1 9v4.3a2 2 0 0 1-2 2H5.5a2 2 0 0 1-2-2V13.5Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Sparkle = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M12 3.5 13.6 9l5.4 1.6-5.4 1.6L12 17.5l-1.6-5.3L5 10.6 10.4 9Z" />
|
||||
<path d="M18.5 16.5 19.2 19l2.3.7-2.3.8-.7 2.4" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Clock = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<circle cx="12" cy="12" r="8.5" />
|
||||
<path d="M12 7.5V12l3 2" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Trash = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M4.5 7h15M9.5 7V5.5A1.5 1.5 0 0 1 11 4h2a1.5 1.5 0 0 1 1.5 1.5V7" />
|
||||
<path d="M6.5 7l.8 11.2A2 2 0 0 0 9.3 20h5.4a2 2 0 0 0 2-1.8L17.5 7" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Lock = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<rect x="4.5" y="10.5" width="15" height="10" rx="2.2" />
|
||||
<path d="M8 10.5V8a4 4 0 0 1 8 0v2.5" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Logout = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M14.5 4.5H7a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h7.5" />
|
||||
<path d="M18 12H10M15.5 8.5 19 12l-3.5 3.5" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Flag = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M6 21V4.5M6 5h10.5l-1.7 3.6L16.5 12H6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Link2 = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<path d="M9.5 14.5 14.5 9.5" />
|
||||
<path d="M11 6.8 12.6 5.2a3.7 3.7 0 0 1 5.2 5.2l-1.6 1.6" />
|
||||
<path d="M13 17.2 11.4 18.8a3.7 3.7 0 0 1-5.2-5.2l1.6-1.6" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const More = (p: IconProps) => (
|
||||
<svg {...base(p)}>
|
||||
<circle cx="6" cy="12" r="1.2" fill="currentColor" stroke="none" />
|
||||
<circle cx="12" cy="12" r="1.2" fill="currentColor" stroke="none" />
|
||||
<circle cx="18" cy="12" r="1.2" fill="currentColor" stroke="none" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Spinner = ({ size = 16, className = "" }: { size?: number; className?: string }) => (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 24 24"
|
||||
className={`animate-spin ${className}`}
|
||||
aria-hidden
|
||||
>
|
||||
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.6" opacity="0.2" fill="none" />
|
||||
<path
|
||||
d="M21 12a9 9 0 0 0-9-9"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.6"
|
||||
strokeLinecap="round"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Logo = ({ size = 28 }: { size?: number }) => (
|
||||
<svg width={size} height={size} viewBox="0 0 32 32" aria-hidden>
|
||||
<rect width="32" height="32" rx="9" fill="#2F6054" />
|
||||
<path
|
||||
d="M9 11.5h14M9 16h9.5M9 20.5h6"
|
||||
stroke="#EFF5F3"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<circle cx="23" cy="20.5" r="3" fill="#C2703D" />
|
||||
</svg>
|
||||
);
|
||||
Reference in New Issue
Block a user