Skip to content

Commit bd6b728

Browse files
committed
feat: enhance PricingTags and SelectableButtonGroup with new badge styles and color variants
1 parent 6f81857 commit bd6b728

9 files changed

Lines changed: 131 additions & 52 deletions

File tree

web/src/components/common/ui/SelectableButtonGroup.jsx

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import { useContainerWidth } from '../../../hooks/common/useContainerWidth';
2323
import {
2424
Divider,
2525
Button,
26-
Tag,
2726
Row,
2827
Col,
2928
Collapsible,
@@ -46,6 +45,7 @@ import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons';
4645
* @param {number} collapseHeight 折叠时的高度,默认200
4746
* @param {boolean} withCheckbox 是否启用前缀 Checkbox 来控制激活状态
4847
* @param {boolean} loading 是否处于加载状态
48+
* @param {string} variant 颜色变体: 'violet' | 'teal' | 'amber' | 'rose' | 'green',不传则使用默认蓝色
4949
*/
5050
const SelectableButtonGroup = ({
5151
title,
@@ -58,6 +58,7 @@ const SelectableButtonGroup = ({
5858
collapseHeight = 200,
5959
withCheckbox = false,
6060
loading = false,
61+
variant,
6162
}) => {
6263
const [isOpen, setIsOpen] = useState(false);
6364
const [skeletonCount] = useState(12);
@@ -178,9 +179,6 @@ const SelectableButtonGroup = ({
178179
) : (
179180
<Row gutter={gutterSize} style={{ lineHeight: '32px', ...style }}>
180181
{items.map((item) => {
181-
const isDisabled =
182-
item.disabled ||
183-
(typeof item.tagCount === 'number' && item.tagCount === 0);
184182
const isActive = Array.isArray(activeValue)
185183
? activeValue.includes(item.value)
186184
: activeValue === item.value;
@@ -194,13 +192,11 @@ const SelectableButtonGroup = ({
194192
}}
195193
theme={isActive ? 'light' : 'outline'}
196194
type={isActive ? 'primary' : 'tertiary'}
197-
disabled={isDisabled}
198195
className='sbg-button'
199196
icon={
200197
<Checkbox
201198
checked={isActive}
202199
onChange={() => onChange(item.value)}
203-
disabled={isDisabled}
204200
style={{ pointerEvents: 'auto' }}
205201
/>
206202
}
@@ -210,14 +206,9 @@ const SelectableButtonGroup = ({
210206
{item.icon && <span className='sbg-icon'>{item.icon}</span>}
211207
<ConditionalTooltipText text={item.label} />
212208
{item.tagCount !== undefined && shouldShowTags && (
213-
<Tag
214-
className='sbg-tag'
215-
color='white'
216-
shape='circle'
217-
size='small'
218-
>
209+
<span className={`sbg-badge ${isActive ? 'sbg-badge-active' : ''}`}>
219210
{item.tagCount}
220-
</Tag>
211+
</span>
221212
)}
222213
</div>
223214
</Button>
@@ -231,22 +222,16 @@ const SelectableButtonGroup = ({
231222
onClick={() => onChange(item.value)}
232223
theme={isActive ? 'light' : 'outline'}
233224
type={isActive ? 'primary' : 'tertiary'}
234-
disabled={isDisabled}
235225
className='sbg-button'
236226
style={{ width: '100%' }}
237227
>
238228
<div className='sbg-content'>
239229
{item.icon && <span className='sbg-icon'>{item.icon}</span>}
240230
<ConditionalTooltipText text={item.label} />
241-
{item.tagCount !== undefined && shouldShowTags && (
242-
<Tag
243-
className='sbg-tag'
244-
color='white'
245-
shape='circle'
246-
size='small'
247-
>
231+
{item.tagCount !== undefined && shouldShowTags && item.tagCount !== '' && (
232+
<span className={`sbg-badge ${isActive ? 'sbg-badge-active' : ''}`}>
248233
{item.tagCount}
249-
</Tag>
234+
</span>
250235
)}
251236
</div>
252237
</Button>
@@ -258,7 +243,7 @@ const SelectableButtonGroup = ({
258243

259244
return (
260245
<div
261-
className={`mb-8 ${containerWidth <= 400 ? 'sbg-compact' : ''}`}
246+
className={`mb-8 ${containerWidth <= 400 ? 'sbg-compact' : ''}${variant ? ` sbg-variant-${variant}` : ''}`}
262247
ref={containerRef}
263248
>
264249
{title && (

web/src/components/table/model-pricing/filter/PricingEndpointTypes.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,13 @@ const PricingEndpointTypes = ({
7676
value: 'all',
7777
label: t('全部端点'),
7878
tagCount: getEndpointTypeCount('all'),
79-
disabled: models.length === 0,
8079
},
8180
...availableEndpointTypes.map((endpointType) => {
8281
const count = getEndpointTypeCount(endpointType);
8382
return {
8483
value: endpointType,
8584
label: getEndpointTypeLabel(endpointType),
8685
tagCount: count,
87-
disabled: count === 0,
8886
};
8987
}),
9088
];
@@ -96,6 +94,7 @@ const PricingEndpointTypes = ({
9694
activeValue={filterEndpointType}
9795
onChange={setFilterEndpointType}
9896
loading={loading}
97+
variant='green'
9998
t={t}
10099
/>
101100
);

web/src/components/table/model-pricing/filter/PricingGroups.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,19 @@ const PricingGroups = ({
5252
.length;
5353
let ratioDisplay = '';
5454
if (g === 'all') {
55-
ratioDisplay = t('全部');
55+
// ratioDisplay = t('全部');
5656
} else {
5757
const ratio = groupRatio[g];
5858
if (ratio !== undefined && ratio !== null) {
59-
ratioDisplay = `x${ratio}`;
59+
ratioDisplay = `${ratio}x`;
6060
} else {
61-
ratioDisplay = 'x1';
61+
ratioDisplay = '1x';
6262
}
6363
}
6464
return {
6565
value: g,
6666
label: g === 'all' ? t('全部分组') : g,
6767
tagCount: ratioDisplay,
68-
disabled: modelCount === 0,
6968
};
7069
});
7170

@@ -76,6 +75,7 @@ const PricingGroups = ({
7675
activeValue={filterGroup}
7776
onChange={setFilterGroup}
7877
loading={loading}
78+
variant='teal'
7979
t={t}
8080
/>
8181
);

web/src/components/table/model-pricing/filter/PricingQuotaTypes.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const PricingQuotaTypes = ({
5252
activeValue={filterQuotaType}
5353
onChange={setFilterQuotaType}
5454
loading={loading}
55+
variant='amber'
5556
t={t}
5657
/>
5758
);

web/src/components/table/model-pricing/filter/PricingTags.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ const PricingTags = ({
7878
value: 'all',
7979
label: t('全部标签'),
8080
tagCount: getTagCount('all'),
81-
disabled: models.length === 0,
8281
},
8382
];
8483

@@ -88,7 +87,6 @@ const PricingTags = ({
8887
value: tag,
8988
label: tag,
9089
tagCount: count,
91-
disabled: count === 0,
9290
});
9391
});
9492

@@ -102,6 +100,7 @@ const PricingTags = ({
102100
activeValue={filterTag}
103101
onChange={setFilterTag}
104102
loading={loading}
103+
variant='rose'
105104
t={t}
106105
/>
107106
);

web/src/components/table/model-pricing/filter/PricingVendors.jsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ const PricingVendors = ({
8383
value: 'all',
8484
label: t('全部供应商'),
8585
tagCount: getVendorCount('all'),
86-
disabled: models.length === 0,
8786
},
8887
];
8988

@@ -96,7 +95,6 @@ const PricingVendors = ({
9695
label: vendor,
9796
icon: icon ? getLobeHubIcon(icon, 16) : null,
9897
tagCount: count,
99-
disabled: count === 0,
10098
});
10199
});
102100

@@ -107,7 +105,6 @@ const PricingVendors = ({
107105
value: 'unknown',
108106
label: t('未知供应商'),
109107
tagCount: count,
110-
disabled: count === 0,
111108
});
112109
}
113110

@@ -121,6 +118,7 @@ const PricingVendors = ({
121118
activeValue={filterVendor}
122119
onChange={setFilterVendor}
123120
loading={loading}
121+
variant='violet'
124122
t={t}
125123
/>
126124
);

web/src/components/table/model-pricing/layout/PricingSidebar.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,6 @@ const PricingSidebar = ({
113113
t={t}
114114
/>
115115

116-
<PricingTags
117-
filterTag={filterTag}
118-
setFilterTag={setFilterTag}
119-
models={tagModels}
120-
allModels={categoryProps.models}
121-
loading={loading}
122-
t={t}
123-
/>
124-
125116
<PricingGroups
126117
filterGroup={filterGroup}
127118
setFilterGroup={handleGroupClick}
@@ -140,6 +131,15 @@ const PricingSidebar = ({
140131
t={t}
141132
/>
142133

134+
<PricingTags
135+
filterTag={filterTag}
136+
setFilterTag={setFilterTag}
137+
models={tagModels}
138+
allModels={categoryProps.models}
139+
loading={loading}
140+
t={t}
141+
/>
142+
143143
<PricingEndpointTypes
144144
filterEndpointType={filterEndpointType}
145145
setFilterEndpointType={setFilterEndpointType}

web/src/components/table/model-pricing/modal/components/FilterModalContent.jsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,6 @@ const FilterModalContent = ({ sidebarProps, t }) => {
9696
t={t}
9797
/>
9898

99-
<PricingTags
100-
filterTag={filterTag}
101-
setFilterTag={setFilterTag}
102-
models={tagModels}
103-
allModels={categoryProps.models}
104-
loading={loading}
105-
t={t}
106-
/>
107-
10899
<PricingGroups
109100
filterGroup={filterGroup}
110101
setFilterGroup={setFilterGroup}
@@ -123,6 +114,16 @@ const FilterModalContent = ({ sidebarProps, t }) => {
123114
t={t}
124115
/>
125116

117+
<PricingTags
118+
filterTag={filterTag}
119+
setFilterTag={setFilterTag}
120+
models={tagModels}
121+
allModels={categoryProps.models}
122+
loading={loading}
123+
t={t}
124+
/>
125+
126+
126127
<PricingEndpointTypes
127128
filterEndpointType={filterEndpointType}
128129
setFilterEndpointType={setFilterEndpointType}

web/src/index.css

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,102 @@ code {
344344
text-overflow: ellipsis;
345345
}
346346

347+
/* Badge for count/multiplier in filter buttons */
348+
.sbg-badge {
349+
display: inline-flex;
350+
align-items: center;
351+
justify-content: center;
352+
flex-shrink: 0;
353+
min-width: 18px;
354+
height: 18px;
355+
padding: 0 6px;
356+
border-radius: 9px;
357+
font-size: 11px;
358+
font-weight: 600;
359+
font-variant-numeric: tabular-nums;
360+
line-height: 1;
361+
background-color: var(--semi-color-fill-0);
362+
color: var(--semi-color-text-2);
363+
transition: background-color 0.15s ease, color 0.15s ease;
364+
}
365+
366+
.sbg-badge-active {
367+
background-color: var(--semi-color-primary-light-active);
368+
color: var(--semi-color-primary);
369+
}
370+
371+
/* ---- SelectableButtonGroup color variants ---- */
372+
.sbg-variant-violet {
373+
--semi-color-primary: #6d28d9;
374+
--semi-color-primary-light-default: rgba(124, 58, 237, 0.08);
375+
--semi-color-primary-light-hover: rgba(124, 58, 237, 0.15);
376+
--semi-color-primary-light-active: rgba(124, 58, 237, 0.22);
377+
}
378+
379+
.sbg-variant-teal {
380+
--semi-color-primary: #0f766e;
381+
--semi-color-primary-light-default: rgba(20, 184, 166, 0.08);
382+
--semi-color-primary-light-hover: rgba(20, 184, 166, 0.15);
383+
--semi-color-primary-light-active: rgba(20, 184, 166, 0.22);
384+
}
385+
386+
.sbg-variant-amber {
387+
--semi-color-primary: #b45309;
388+
--semi-color-primary-light-default: rgba(245, 158, 11, 0.08);
389+
--semi-color-primary-light-hover: rgba(245, 158, 11, 0.15);
390+
--semi-color-primary-light-active: rgba(245, 158, 11, 0.22);
391+
}
392+
393+
.sbg-variant-rose {
394+
--semi-color-primary: #be123c;
395+
--semi-color-primary-light-default: rgba(244, 63, 94, 0.08);
396+
--semi-color-primary-light-hover: rgba(244, 63, 94, 0.15);
397+
--semi-color-primary-light-active: rgba(244, 63, 94, 0.22);
398+
}
399+
400+
.sbg-variant-green {
401+
--semi-color-primary: #047857;
402+
--semi-color-primary-light-default: rgba(16, 185, 129, 0.08);
403+
--semi-color-primary-light-hover: rgba(16, 185, 129, 0.15);
404+
--semi-color-primary-light-active: rgba(16, 185, 129, 0.22);
405+
}
406+
407+
/* Dark mode: lighter text, slightly stronger backgrounds */
408+
html.dark .sbg-variant-violet {
409+
--semi-color-primary: #a78bfa;
410+
--semi-color-primary-light-default: rgba(139, 92, 246, 0.14);
411+
--semi-color-primary-light-hover: rgba(139, 92, 246, 0.22);
412+
--semi-color-primary-light-active: rgba(139, 92, 246, 0.3);
413+
}
414+
415+
html.dark .sbg-variant-teal {
416+
--semi-color-primary: #2dd4bf;
417+
--semi-color-primary-light-default: rgba(45, 212, 191, 0.14);
418+
--semi-color-primary-light-hover: rgba(45, 212, 191, 0.22);
419+
--semi-color-primary-light-active: rgba(45, 212, 191, 0.3);
420+
}
421+
422+
html.dark .sbg-variant-amber {
423+
--semi-color-primary: #fbbf24;
424+
--semi-color-primary-light-default: rgba(251, 191, 36, 0.14);
425+
--semi-color-primary-light-hover: rgba(251, 191, 36, 0.22);
426+
--semi-color-primary-light-active: rgba(251, 191, 36, 0.3);
427+
}
428+
429+
html.dark .sbg-variant-rose {
430+
--semi-color-primary: #fb7185;
431+
--semi-color-primary-light-default: rgba(251, 113, 133, 0.14);
432+
--semi-color-primary-light-hover: rgba(251, 113, 133, 0.22);
433+
--semi-color-primary-light-active: rgba(251, 113, 133, 0.3);
434+
}
435+
436+
html.dark .sbg-variant-green {
437+
--semi-color-primary: #34d399;
438+
--semi-color-primary-light-default: rgba(52, 211, 153, 0.14);
439+
--semi-color-primary-light-hover: rgba(52, 211, 153, 0.22);
440+
--semi-color-primary-light-active: rgba(52, 211, 153, 0.3);
441+
}
442+
347443
/* Tabs组件样式 */
348444
.semi-tabs-content {
349445
padding: 0 !important;

0 commit comments

Comments
 (0)