feat: 服装搭配页面UI美化和UX改进
UI优化内容: - 重新设计页面头部,使用优雅的渐变背景和现代化图标 - 优化标签导航,采用卡片式设计和平滑动画效果 - 美化搜索面板,改进输入框、筛选器和按钮的视觉设计 - 重构图片上传组件,添加拖拽区域样式和上传进度动画 - 优化搜索结果展示,使用网格布局和悬停效果 - 改进AI分析结果展示,采用卡片式布局和颜色编码 - 增强LLM聊天界面,现代化消息气泡和打字动画 响应式设计: - 实现移动优先的响应式布局 - 优化平板端和桌面端适配 - 修复1200px宽度下的左右布局显示问题 - 添加触摸友好的交互元素 用户体验提升: - 统一设计语言和视觉风格 - 添加流畅的页面切换和组件加载动画 - 优化加载状态、错误提示和空状态设计 - 改进信息层次和视觉可读性 技术改进: - 使用Tailwind CSS类替代内联样式 - 统一使用Lucide React图标库 - 完善CSS变量和设计令牌系统 - 添加兼容性变量支持旧的命名格式 符合promptx/frontend-developer规定的前端开发规范,确保界面美观、操作流畅、动画优美,符合用户操作习惯和大众审美习惯。
This commit is contained in:
300
apps/desktop/src/utils/colorUtils.ts
Normal file
300
apps/desktop/src/utils/colorUtils.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
import { ColorHSV } from '../types/outfitSearch';
|
||||
|
||||
/**
|
||||
* 颜色工具函数
|
||||
* 遵循 Tauri 开发规范的工具函数设计原则
|
||||
*/
|
||||
|
||||
/**
|
||||
* HSV颜色转换为十六进制字符串
|
||||
*/
|
||||
export function hsvToHex(color: ColorHSV): string {
|
||||
const [r, g, b] = hsvToRgb(color);
|
||||
return `#${Math.round(r).toString(16).padStart(2, '0')}${Math.round(g).toString(16).padStart(2, '0')}${Math.round(b).toString(16).padStart(2, '0')}`.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 十六进制字符串转换为HSV颜色
|
||||
*/
|
||||
export function hexToHsv(hex: string): ColorHSV {
|
||||
const cleanHex = hex.replace('#', '');
|
||||
if (cleanHex.length !== 6) {
|
||||
throw new Error('Invalid hex color format');
|
||||
}
|
||||
|
||||
const r = parseInt(cleanHex.substring(0, 2), 16);
|
||||
const g = parseInt(cleanHex.substring(2, 4), 16);
|
||||
const b = parseInt(cleanHex.substring(4, 6), 16);
|
||||
|
||||
return rgbToHsv(r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB值转换为HSV颜色
|
||||
*/
|
||||
export function rgbToHsv(r: number, g: number, b: number): ColorHSV {
|
||||
r = r / 255;
|
||||
g = g / 255;
|
||||
b = b / 255;
|
||||
|
||||
const max = Math.max(r, g, b);
|
||||
const min = Math.min(r, g, b);
|
||||
const delta = max - min;
|
||||
|
||||
let hue = 0;
|
||||
if (delta !== 0) {
|
||||
if (max === r) {
|
||||
hue = ((g - b) / delta) % 6;
|
||||
} else if (max === g) {
|
||||
hue = (b - r) / delta + 2;
|
||||
} else {
|
||||
hue = (r - g) / delta + 4;
|
||||
}
|
||||
hue = hue / 6;
|
||||
}
|
||||
|
||||
const saturation = max === 0 ? 0 : delta / max;
|
||||
const value = max;
|
||||
|
||||
return {
|
||||
hue: Math.max(0, Math.min(1, hue)),
|
||||
saturation: Math.max(0, Math.min(1, saturation)),
|
||||
value: Math.max(0, Math.min(1, value)),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* HSV颜色转换为RGB值
|
||||
*/
|
||||
export function hsvToRgb(color: ColorHSV): [number, number, number] {
|
||||
const { hue, saturation, value } = color;
|
||||
|
||||
const c = value * saturation;
|
||||
const x = c * (1 - Math.abs(((hue * 6) % 2) - 1));
|
||||
const m = value - c;
|
||||
|
||||
let r = 0, g = 0, b = 0;
|
||||
|
||||
const hueSegment = Math.floor(hue * 6);
|
||||
switch (hueSegment) {
|
||||
case 0:
|
||||
r = c; g = x; b = 0;
|
||||
break;
|
||||
case 1:
|
||||
r = x; g = c; b = 0;
|
||||
break;
|
||||
case 2:
|
||||
r = 0; g = c; b = x;
|
||||
break;
|
||||
case 3:
|
||||
r = 0; g = x; b = c;
|
||||
break;
|
||||
case 4:
|
||||
r = x; g = 0; b = c;
|
||||
break;
|
||||
case 5:
|
||||
r = c; g = 0; b = x;
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
Math.round((r + m) * 255),
|
||||
Math.round((g + m) * 255),
|
||||
Math.round((b + m) * 255),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个颜色的距离
|
||||
*/
|
||||
export function colorDistance(color1: ColorHSV, color2: ColorHSV): number {
|
||||
// 色相环形距离计算
|
||||
const hueDiff = Math.abs(color1.hue - color2.hue);
|
||||
const hueDistance = Math.min(hueDiff, 1 - hueDiff);
|
||||
|
||||
// 饱和度和明度线性距离
|
||||
const satDistance = Math.abs(color1.saturation - color2.saturation);
|
||||
const valDistance = Math.abs(color1.value - color2.value);
|
||||
|
||||
// 加权距离计算:色相50%,饱和度30%,明度20%
|
||||
return hueDistance * 0.5 + satDistance * 0.3 + valDistance * 0.2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算颜色相似度 (0-1,1表示完全相同)
|
||||
*/
|
||||
export function colorSimilarity(color1: ColorHSV, color2: ColorHSV): number {
|
||||
return 1 - colorDistance(color1, color2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断颜色是否在指定阈值范围内匹配
|
||||
*/
|
||||
export function colorsMatch(
|
||||
color1: ColorHSV,
|
||||
color2: ColorHSV,
|
||||
hueThreshold: number = 0.05,
|
||||
satThreshold: number = 0.05,
|
||||
valThreshold: number = 0.20
|
||||
): boolean {
|
||||
const hueDiff = Math.abs(color1.hue - color2.hue);
|
||||
const hueDistance = Math.min(hueDiff, 1 - hueDiff);
|
||||
const satDiff = Math.abs(color1.saturation - color2.saturation);
|
||||
const valDiff = Math.abs(color1.value - color2.value);
|
||||
|
||||
return hueDistance <= hueThreshold &&
|
||||
satDiff <= satThreshold &&
|
||||
valDiff <= valThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成颜色的互补色
|
||||
*/
|
||||
export function getComplementaryColor(color: ColorHSV): ColorHSV {
|
||||
return {
|
||||
hue: (color.hue + 0.5) % 1,
|
||||
saturation: color.saturation,
|
||||
value: color.value,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成颜色的类似色(相邻色)
|
||||
*/
|
||||
export function getAnalogousColors(color: ColorHSV, count: number = 2): ColorHSV[] {
|
||||
const colors: ColorHSV[] = [];
|
||||
const step = 0.083; // 30度 / 360度 = 0.083
|
||||
|
||||
for (let i = 1; i <= count; i++) {
|
||||
colors.push({
|
||||
hue: (color.hue + step * i) % 1,
|
||||
saturation: color.saturation,
|
||||
value: color.value,
|
||||
});
|
||||
|
||||
colors.push({
|
||||
hue: (color.hue - step * i + 1) % 1,
|
||||
saturation: color.saturation,
|
||||
value: color.value,
|
||||
});
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成颜色的三元色
|
||||
*/
|
||||
export function getTriadicColors(color: ColorHSV): ColorHSV[] {
|
||||
return [
|
||||
{
|
||||
hue: (color.hue + 0.333) % 1,
|
||||
saturation: color.saturation,
|
||||
value: color.value,
|
||||
},
|
||||
{
|
||||
hue: (color.hue + 0.667) % 1,
|
||||
saturation: color.saturation,
|
||||
value: color.value,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整颜色亮度
|
||||
*/
|
||||
export function adjustBrightness(color: ColorHSV, factor: number): ColorHSV {
|
||||
return {
|
||||
hue: color.hue,
|
||||
saturation: color.saturation,
|
||||
value: Math.max(0, Math.min(1, color.value * factor)),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整颜色饱和度
|
||||
*/
|
||||
export function adjustSaturation(color: ColorHSV, factor: number): ColorHSV {
|
||||
return {
|
||||
hue: color.hue,
|
||||
saturation: Math.max(0, Math.min(1, color.saturation * factor)),
|
||||
value: color.value,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取颜色的可读性文本颜色(黑色或白色)
|
||||
*/
|
||||
export function getContrastTextColor(color: ColorHSV): string {
|
||||
const [r, g, b] = hsvToRgb(color);
|
||||
|
||||
// 计算相对亮度
|
||||
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||||
|
||||
return luminance > 0.5 ? '#000000' : '#FFFFFF';
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证HSV颜色值的有效性
|
||||
*/
|
||||
export function isValidHSV(color: ColorHSV): boolean {
|
||||
return (
|
||||
typeof color.hue === 'number' && color.hue >= 0 && color.hue <= 1 &&
|
||||
typeof color.saturation === 'number' && color.saturation >= 0 && color.saturation <= 1 &&
|
||||
typeof color.value === 'number' && color.value >= 0 && color.value <= 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建默认HSV颜色
|
||||
*/
|
||||
export function createDefaultHSV(): ColorHSV {
|
||||
return { hue: 0, saturation: 0, value: 0.5 };
|
||||
}
|
||||
|
||||
/**
|
||||
* 从CSS颜色名称转换为HSV
|
||||
*/
|
||||
export function cssColorToHsv(cssColor: string): ColorHSV {
|
||||
// 创建临时元素来获取计算后的颜色
|
||||
const div = document.createElement('div');
|
||||
div.style.color = cssColor;
|
||||
document.body.appendChild(div);
|
||||
|
||||
const computedColor = window.getComputedStyle(div).color;
|
||||
document.body.removeChild(div);
|
||||
|
||||
// 解析 rgb(r, g, b) 格式
|
||||
const rgbMatch = computedColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
||||
if (rgbMatch) {
|
||||
const r = parseInt(rgbMatch[1]);
|
||||
const g = parseInt(rgbMatch[2]);
|
||||
const b = parseInt(rgbMatch[3]);
|
||||
return rgbToHsv(r, g, b);
|
||||
}
|
||||
|
||||
// 如果解析失败,返回默认颜色
|
||||
return createDefaultHSV();
|
||||
}
|
||||
|
||||
/**
|
||||
* 颜色工具对象
|
||||
*/
|
||||
export const ColorUtils = {
|
||||
hsvToHex,
|
||||
hexToHsv,
|
||||
rgbToHsv,
|
||||
hsvToRgb,
|
||||
colorDistance,
|
||||
colorSimilarity,
|
||||
colorsMatch,
|
||||
getComplementaryColor,
|
||||
getAnalogousColors,
|
||||
getTriadicColors,
|
||||
adjustBrightness,
|
||||
adjustSaturation,
|
||||
getContrastTextColor,
|
||||
isValidHSV,
|
||||
createDefaultHSV,
|
||||
cssColorToHsv,
|
||||
};
|
||||
Reference in New Issue
Block a user