chore: 优化外观颜色选择器交互

This commit is contained in:
qinhaoyan 2024-10-21 20:27:03 +08:00 committed by lmaomaoz
parent 7d84805605
commit 7767ab7df0
2 changed files with 71 additions and 118 deletions

View File

@ -443,6 +443,7 @@ function GradientColor(props: ThemeColorProps) {
currentIndex = i;
window.addEventListener('mousemove', handleMoveSliderItem);
window.addEventListener('mouseup', handleUpSliderItem);
document.body.classList.add('gradientColor-move');
}
// 移动渐变点
@ -456,7 +457,6 @@ function GradientColor(props: ThemeColorProps) {
tempColors.splice(currentIndex, 1);
setIndex(0);
setColors(tempColors);
gradientChange(range, tempColors);
}
// 限制不能超过最大、最小值
else if (itemPosition >= 0 && itemPosition <= 100) {
@ -482,7 +482,6 @@ function GradientColor(props: ThemeColorProps) {
setIndex(currentIndex + 1);
}
setColors(tempColors);
gradientChange(range, tempColors);
}
}
@ -490,9 +489,15 @@ function GradientColor(props: ThemeColorProps) {
function handleUpSliderItem() {
window.removeEventListener('mousemove', handleMoveSliderItem);
window.removeEventListener('mouseup', handleUpSliderItem);
document.body.classList.remove('gradientColor-move');
setTimeout(() => {
setMove(false);
}, 0);
setColors(colors => {
gradientChange(range, colors);
return colors;
});
}
// 通过角度计算位置
@ -508,6 +513,7 @@ function GradientColor(props: ThemeColorProps) {
// 按下渐变角度句柄
function handleDownRange() {
document.body.classList.add('gradientColor-move');
window.addEventListener('mousemove', handleMoveRange);
window.addEventListener('mouseup', handleUpRange);
}
@ -533,13 +539,22 @@ function GradientColor(props: ThemeColorProps) {
angle = 360 - angle;
}
setRange(angle);
gradientChange(angle, colors);
}
// 抬起渐变角度句柄
function handleUpRange() {
document.body.classList.remove('gradientColor-move');
window.removeEventListener('mousemove', handleMoveRange);
window.removeEventListener('mouseup', handleUpRange);
setRange(range => {
gradientChange(range, colors);
return range;
});
}
function handelSetRange() {
setRangeShow(false);
window.removeEventListener('click', handelSetRange);
}
return (
@ -577,23 +592,17 @@ function GradientColor(props: ThemeColorProps) {
);
})}
</div>
<div
className="Theme-GradientColor-range"
ref={rangeRef}
onClick={e => {
setRangeShow(true);
e.stopPropagation();
window.addEventListener('click', () => {
setRangeShow(false);
});
}}
>
<div className="Theme-GradientColor-range" ref={rangeRef}>
<NumberInput
formatter={(value: string | number) => value + '°'}
max={360}
min={0}
value={range}
onChange={rangeChange}
onFocus={() => {
setRangeShow(true);
window.addEventListener('click', handelSetRange);
}}
/>
<Overlay
// @ts-ignore
@ -1123,22 +1132,21 @@ function ColorSelect(props: ColorSelectProps) {
needCustom
} = props;
const [tab, setTab] = useState('color');
const [subTab, setSubTab] = useState(0);
const presetColorRef = useRef<any>();
const tabMap: any = {
color: {name: 'color'}
color: {name: 'color', label: '主题颜色'}
};
if (needCustom) {
tabMap['custom'] = {name: 'custom', label: '自定义颜色'};
}
if (needGradient) {
tabMap['gradient'] = {name: 'gradient'};
tabMap['gradient'] = {name: 'gradient', label: '渐变'};
}
if (needImage) {
tabMap['img'] = {
name: 'img',
icon: <ThemeIcon icon="color-picker-img" />,
activeIcon: <ThemeIcon icon="color-picker-img-active" />
};
tabMap['img'] = {name: 'img', label: '图片'};
}
const subTabList: any[] = [
needTheme &&
themeList &&
@ -1146,74 +1154,29 @@ function ColorSelect(props: ColorSelectProps) {
needCustom && {name: '自定义颜色', parent: 'color', id: 1}
].filter(n => n);
function setSubTabCheck() {
if (
needTheme &&
value.indexOf('#') !== 0 &&
value.indexOf('rgba') !== 0 &&
subTabList.find(item => item.id === 0)
) {
setSubTab(0);
} else if (needCustom && subTabList.find(item => item.id === 1)) {
setSubTab(1);
}
}
useEffect(() => {
if (
needTheme &&
(value?.indexOf('var') === 0 || value === 'transparent' || !value) &&
subTabList.find(item => item.id === 0)
(value?.indexOf('var') === 0 || value === 'transparent' || !value)
) {
setTab('color');
setSubTab(0);
} else if (
needCustom &&
(value?.startsWith('rgb') || value?.startsWith('#'))
) {
setTab('custom');
} else if (needGradient && value?.indexOf('linear-gradient') === 0) {
setTab('gradient');
} else if (needImage && value?.indexOf('url') === 0) {
setTab('img');
} else if (needCustom && subTabList.find(item => item.id === 1)) {
setTab('color');
setSubTab(1);
}
}, [show]);
useEffect(() => {
if (needTheme) {
setSubTab(0);
} else if (needCustom) {
setSubTab(1);
}
}, [needCustom, needTheme]);
function colorOnChange(value: string) {
onChange(value);
presetColorRef.current?.setPresetColor(value);
}
function renderSubTab() {
const list = subTabList.filter(item => item.parent === tab);
if (list.length > 0) {
return (
<div className="Theme-ColorSelect-tab-sub">
{list.map((item: any) => (
<div
key={item.id}
className={cx(
'Theme-ColorSelect-tab-sub-item',
subTab === item.id && 'Theme-ColorSelect-tab-sub--active'
)}
onClick={() => setSubTab(item.id)}
>
{item.name}
</div>
))}
</div>
);
} else {
return null;
}
}
return (
<Overlay
// @ts-ignore
@ -1231,39 +1194,32 @@ function ColorSelect(props: ColorSelectProps) {
key={key}
className={cx(
'Theme-ColorSelect-tab-' + key,
tab === key && `Theme-ColorSelect-tab-${key}--active`
tab === key && 'Theme-ColorSelect-tab--active'
)}
onClick={() => {
setTab(key);
setSubTabCheck();
}}
>
{tab === key ? tabMap[key].activeIcon : tabMap[key].icon}
{tabMap[key].label}
</div>
))}
</div>
) : null}
{renderSubTab()}
<div className="Theme-ColorSelect-content">
{tab === 'color' ? (
<div className="Theme-ColorSelect-content-color">
{subTab === 0 ? (
<ThemeColorList
{...props}
themeList={themeList}
onChange={colorOnChange}
value={value}
/>
) : null}
{subTab === 1 ? (
<CustomColor
onChange={colorOnChange}
value={value}
themeList={themeList}
/>
) : null}
</div>
<ThemeColorList
{...props}
themeList={themeList}
onChange={colorOnChange}
value={value}
/>
) : null}
{tab === 'custom' ? (
<CustomColor
onChange={colorOnChange}
value={value}
themeList={themeList}
/>
) : null}
{tab === 'gradient' ? (
<GradientColor

View File

@ -88,35 +88,16 @@ $ns: cxd-;
&-tab {
display: flex;
padding: px2rem(14px) px2rem(12px);
border: 1px solid #e8e9eb;
border-bottom: 1px solid #e8e9eb;
& > div {
height: px2rem(16px);
width: px2rem(16px);
border-radius: 50%;
margin-right: px2rem(12px);
font-size: 12px;
cursor: pointer;
& > svg {
height: px2rem(16px);
width: px2rem(16px);
}
}
&-color {
background-color: #e8e9eb;
}
&-color--active {
background: #d4e5ff;
border: 1px solid #2468f2;
}
&-gradient {
background-image: linear-gradient(180deg, #f4f4f4 0%, #b8babf 100%);
}
&-gradient--active {
background-image: linear-gradient(180deg, #ffffff 0%, #6296ff 99%);
border: 1px solid #2468f2;
}
&-img--active > svg {
border: 1px solid #2468f2;
border-radius: 50%;
&--active {
color: #2468f2;
}
}
&-tab {
@ -598,3 +579,19 @@ $ns: cxd-;
z-index: 1500;
}
}
.gradientColor-move {
&::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 10000000;
cursor: pointer;
}
* {
user-select: none;
}
}