Bladeren bron

feat: enhance PricingTags and SelectableButtonGroup with new badge styles and color variants

CaIon 3 dagen geleden
bovenliggende
commit
c31f9db61e

+ 8 - 23
web/src/components/common/ui/SelectableButtonGroup.jsx

@@ -23,7 +23,6 @@ import { useContainerWidth } from '../../../hooks/common/useContainerWidth';
 import {
   Divider,
   Button,
-  Tag,
   Row,
   Col,
   Collapsible,
@@ -46,6 +45,7 @@ import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons';
  * @param {number} collapseHeight 折叠时的高度,默认200
  * @param {boolean} withCheckbox 是否启用前缀 Checkbox 来控制激活状态
  * @param {boolean} loading 是否处于加载状态
+ * @param {string} variant 颜色变体: 'violet' | 'teal' | 'amber' | 'rose' | 'green',不传则使用默认蓝色
  */
 const SelectableButtonGroup = ({
   title,
@@ -58,6 +58,7 @@ const SelectableButtonGroup = ({
   collapseHeight = 200,
   withCheckbox = false,
   loading = false,
+  variant,
 }) => {
   const [isOpen, setIsOpen] = useState(false);
   const [skeletonCount] = useState(12);
@@ -178,9 +179,6 @@ const SelectableButtonGroup = ({
   ) : (
     <Row gutter={gutterSize} style={{ lineHeight: '32px', ...style }}>
       {items.map((item) => {
-        const isDisabled =
-          item.disabled ||
-          (typeof item.tagCount === 'number' && item.tagCount === 0);
         const isActive = Array.isArray(activeValue)
           ? activeValue.includes(item.value)
           : activeValue === item.value;
@@ -194,13 +192,11 @@ const SelectableButtonGroup = ({
                 }}
                 theme={isActive ? 'light' : 'outline'}
                 type={isActive ? 'primary' : 'tertiary'}
-                disabled={isDisabled}
                 className='sbg-button'
                 icon={
                   <Checkbox
                     checked={isActive}
                     onChange={() => onChange(item.value)}
-                    disabled={isDisabled}
                     style={{ pointerEvents: 'auto' }}
                   />
                 }
@@ -210,14 +206,9 @@ const SelectableButtonGroup = ({
                   {item.icon && <span className='sbg-icon'>{item.icon}</span>}
                   <ConditionalTooltipText text={item.label} />
                   {item.tagCount !== undefined && shouldShowTags && (
-                    <Tag
-                      className='sbg-tag'
-                      color='white'
-                      shape='circle'
-                      size='small'
-                    >
+                    <span className={`sbg-badge ${isActive ? 'sbg-badge-active' : ''}`}>
                       {item.tagCount}
-                    </Tag>
+                    </span>
                   )}
                 </div>
               </Button>
@@ -231,22 +222,16 @@ const SelectableButtonGroup = ({
               onClick={() => onChange(item.value)}
               theme={isActive ? 'light' : 'outline'}
               type={isActive ? 'primary' : 'tertiary'}
-              disabled={isDisabled}
               className='sbg-button'
               style={{ width: '100%' }}
             >
               <div className='sbg-content'>
                 {item.icon && <span className='sbg-icon'>{item.icon}</span>}
                 <ConditionalTooltipText text={item.label} />
-                {item.tagCount !== undefined && shouldShowTags && (
-                  <Tag
-                    className='sbg-tag'
-                    color='white'
-                    shape='circle'
-                    size='small'
-                  >
+                {item.tagCount !== undefined && shouldShowTags && item.tagCount !== '' && (
+                  <span className={`sbg-badge ${isActive ? 'sbg-badge-active' : ''}`}>
                     {item.tagCount}
-                  </Tag>
+                  </span>
                 )}
               </div>
             </Button>
@@ -258,7 +243,7 @@ const SelectableButtonGroup = ({
 
   return (
     <div
-      className={`mb-8 ${containerWidth <= 400 ? 'sbg-compact' : ''}`}
+      className={`mb-8 ${containerWidth <= 400 ? 'sbg-compact' : ''}${variant ? ` sbg-variant-${variant}` : ''}`}
       ref={containerRef}
     >
       {title && (

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

@@ -76,7 +76,6 @@ const PricingEndpointTypes = ({
       value: 'all',
       label: t('全部端点'),
       tagCount: getEndpointTypeCount('all'),
-      disabled: models.length === 0,
     },
     ...availableEndpointTypes.map((endpointType) => {
       const count = getEndpointTypeCount(endpointType);
@@ -84,7 +83,6 @@ const PricingEndpointTypes = ({
         value: endpointType,
         label: getEndpointTypeLabel(endpointType),
         tagCount: count,
-        disabled: count === 0,
       };
     }),
   ];
@@ -96,6 +94,7 @@ const PricingEndpointTypes = ({
       activeValue={filterEndpointType}
       onChange={setFilterEndpointType}
       loading={loading}
+      variant='green'
       t={t}
     />
   );

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

@@ -52,20 +52,19 @@ const PricingGroups = ({
             .length;
     let ratioDisplay = '';
     if (g === 'all') {
-      ratioDisplay = t('全部');
+      // ratioDisplay = t('全部');
     } else {
       const ratio = groupRatio[g];
       if (ratio !== undefined && ratio !== null) {
-        ratioDisplay = `x${ratio}`;
+        ratioDisplay = `${ratio}x`;
       } else {
-        ratioDisplay = 'x1';
+        ratioDisplay = '1x';
       }
     }
     return {
       value: g,
       label: g === 'all' ? t('全部分组') : g,
       tagCount: ratioDisplay,
-      disabled: modelCount === 0,
     };
   });
 
@@ -76,6 +75,7 @@ const PricingGroups = ({
       activeValue={filterGroup}
       onChange={setFilterGroup}
       loading={loading}
+      variant='teal'
       t={t}
     />
   );

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

@@ -52,6 +52,7 @@ const PricingQuotaTypes = ({
       activeValue={filterQuotaType}
       onChange={setFilterQuotaType}
       loading={loading}
+      variant='amber'
       t={t}
     />
   );

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

@@ -78,7 +78,6 @@ const PricingTags = ({
         value: 'all',
         label: t('全部标签'),
         tagCount: getTagCount('all'),
-        disabled: models.length === 0,
       },
     ];
 
@@ -88,7 +87,6 @@ const PricingTags = ({
         value: tag,
         label: tag,
         tagCount: count,
-        disabled: count === 0,
       });
     });
 
@@ -102,6 +100,7 @@ const PricingTags = ({
       activeValue={filterTag}
       onChange={setFilterTag}
       loading={loading}
+      variant='rose'
       t={t}
     />
   );

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

@@ -83,7 +83,6 @@ const PricingVendors = ({
         value: 'all',
         label: t('全部供应商'),
         tagCount: getVendorCount('all'),
-        disabled: models.length === 0,
       },
     ];
 
@@ -96,7 +95,6 @@ const PricingVendors = ({
         label: vendor,
         icon: icon ? getLobeHubIcon(icon, 16) : null,
         tagCount: count,
-        disabled: count === 0,
       });
     });
 
@@ -107,7 +105,6 @@ const PricingVendors = ({
         value: 'unknown',
         label: t('未知供应商'),
         tagCount: count,
-        disabled: count === 0,
       });
     }
 
@@ -121,6 +118,7 @@ const PricingVendors = ({
       activeValue={filterVendor}
       onChange={setFilterVendor}
       loading={loading}
+      variant='violet'
       t={t}
     />
   );

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

@@ -113,15 +113,6 @@ const PricingSidebar = ({
         t={t}
       />
 
-      <PricingTags
-        filterTag={filterTag}
-        setFilterTag={setFilterTag}
-        models={tagModels}
-        allModels={categoryProps.models}
-        loading={loading}
-        t={t}
-      />
-
       <PricingGroups
         filterGroup={filterGroup}
         setFilterGroup={handleGroupClick}
@@ -140,6 +131,15 @@ const PricingSidebar = ({
         t={t}
       />
 
+      <PricingTags
+        filterTag={filterTag}
+        setFilterTag={setFilterTag}
+        models={tagModels}
+        allModels={categoryProps.models}
+        loading={loading}
+        t={t}
+      />
+
       <PricingEndpointTypes
         filterEndpointType={filterEndpointType}
         setFilterEndpointType={setFilterEndpointType}

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

@@ -96,15 +96,6 @@ const FilterModalContent = ({ sidebarProps, t }) => {
         t={t}
       />
 
-      <PricingTags
-        filterTag={filterTag}
-        setFilterTag={setFilterTag}
-        models={tagModels}
-        allModels={categoryProps.models}
-        loading={loading}
-        t={t}
-      />
-
       <PricingGroups
         filterGroup={filterGroup}
         setFilterGroup={setFilterGroup}
@@ -123,6 +114,16 @@ const FilterModalContent = ({ sidebarProps, t }) => {
         t={t}
       />
 
+      <PricingTags
+        filterTag={filterTag}
+        setFilterTag={setFilterTag}
+        models={tagModels}
+        allModels={categoryProps.models}
+        loading={loading}
+        t={t}
+      />
+
+
       <PricingEndpointTypes
         filterEndpointType={filterEndpointType}
         setFilterEndpointType={setFilterEndpointType}

+ 96 - 0
web/src/index.css

@@ -344,6 +344,102 @@ code {
   text-overflow: ellipsis;
 }
 
+/* Badge for count/multiplier in filter buttons */
+.sbg-badge {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  min-width: 18px;
+  height: 18px;
+  padding: 0 6px;
+  border-radius: 9px;
+  font-size: 11px;
+  font-weight: 600;
+  font-variant-numeric: tabular-nums;
+  line-height: 1;
+  background-color: var(--semi-color-fill-0);
+  color: var(--semi-color-text-2);
+  transition: background-color 0.15s ease, color 0.15s ease;
+}
+
+.sbg-badge-active {
+  background-color: var(--semi-color-primary-light-active);
+  color: var(--semi-color-primary);
+}
+
+/* ---- SelectableButtonGroup color variants ---- */
+.sbg-variant-violet {
+  --semi-color-primary: #6d28d9;
+  --semi-color-primary-light-default: rgba(124, 58, 237, 0.08);
+  --semi-color-primary-light-hover: rgba(124, 58, 237, 0.15);
+  --semi-color-primary-light-active: rgba(124, 58, 237, 0.22);
+}
+
+.sbg-variant-teal {
+  --semi-color-primary: #0f766e;
+  --semi-color-primary-light-default: rgba(20, 184, 166, 0.08);
+  --semi-color-primary-light-hover: rgba(20, 184, 166, 0.15);
+  --semi-color-primary-light-active: rgba(20, 184, 166, 0.22);
+}
+
+.sbg-variant-amber {
+  --semi-color-primary: #b45309;
+  --semi-color-primary-light-default: rgba(245, 158, 11, 0.08);
+  --semi-color-primary-light-hover: rgba(245, 158, 11, 0.15);
+  --semi-color-primary-light-active: rgba(245, 158, 11, 0.22);
+}
+
+.sbg-variant-rose {
+  --semi-color-primary: #be123c;
+  --semi-color-primary-light-default: rgba(244, 63, 94, 0.08);
+  --semi-color-primary-light-hover: rgba(244, 63, 94, 0.15);
+  --semi-color-primary-light-active: rgba(244, 63, 94, 0.22);
+}
+
+.sbg-variant-green {
+  --semi-color-primary: #047857;
+  --semi-color-primary-light-default: rgba(16, 185, 129, 0.08);
+  --semi-color-primary-light-hover: rgba(16, 185, 129, 0.15);
+  --semi-color-primary-light-active: rgba(16, 185, 129, 0.22);
+}
+
+/* Dark mode: lighter text, slightly stronger backgrounds */
+html.dark .sbg-variant-violet {
+  --semi-color-primary: #a78bfa;
+  --semi-color-primary-light-default: rgba(139, 92, 246, 0.14);
+  --semi-color-primary-light-hover: rgba(139, 92, 246, 0.22);
+  --semi-color-primary-light-active: rgba(139, 92, 246, 0.3);
+}
+
+html.dark .sbg-variant-teal {
+  --semi-color-primary: #2dd4bf;
+  --semi-color-primary-light-default: rgba(45, 212, 191, 0.14);
+  --semi-color-primary-light-hover: rgba(45, 212, 191, 0.22);
+  --semi-color-primary-light-active: rgba(45, 212, 191, 0.3);
+}
+
+html.dark .sbg-variant-amber {
+  --semi-color-primary: #fbbf24;
+  --semi-color-primary-light-default: rgba(251, 191, 36, 0.14);
+  --semi-color-primary-light-hover: rgba(251, 191, 36, 0.22);
+  --semi-color-primary-light-active: rgba(251, 191, 36, 0.3);
+}
+
+html.dark .sbg-variant-rose {
+  --semi-color-primary: #fb7185;
+  --semi-color-primary-light-default: rgba(251, 113, 133, 0.14);
+  --semi-color-primary-light-hover: rgba(251, 113, 133, 0.22);
+  --semi-color-primary-light-active: rgba(251, 113, 133, 0.3);
+}
+
+html.dark .sbg-variant-green {
+  --semi-color-primary: #34d399;
+  --semi-color-primary-light-default: rgba(52, 211, 153, 0.14);
+  --semi-color-primary-light-hover: rgba(52, 211, 153, 0.22);
+  --semi-color-primary-light-active: rgba(52, 211, 153, 0.3);
+}
+
 /* Tabs组件样式 */
 .semi-tabs-content {
   padding: 0 !important;