💄 style(ui): replace inline gradients with reusable pastel blur balls; improve dark mode

- Introduce a global CSS utility `with-pastel-balls` in `web/src/index.css`, rendering pastel “blur balls” via ::before with CSS variables (`--pb1..--pb4`, `--pb-opacity`, `--pb-blur`) for easy theming.
- Apply the utility to pricing header cards and skeletons:
  - `web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx`
  - `web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx`
- Remove per-component inline `linear-gradient(...)` backgrounds and redundant absolute-positioned decoration nodes to reduce duplication.
- Dark mode:
  - Keep the same pastel palette (pink/lavender/mint/peach).
  - Increase visibility with `--pb-opacity: 0.36`, `--pb-blur: 65px`, and `mix-blend-mode: screen`.
- No functional logic changes; UI-only. Lint passes.

Affected files:
- web/src/index.css
- web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
- web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx
This commit is contained in:
t0ng7u
2025-08-09 21:40:32 +08:00
parent 24860fdc05
commit 0727353afa
4 changed files with 140 additions and 6 deletions

View File

@@ -166,7 +166,7 @@ const PricingVendorIntro = ({
if (filterVendor === 'all') {
return (
<div className='mb-4'>
<Card className="!rounded-2xl" bodyStyle={{ padding: '16px' }}>
<Card className="!rounded-2xl with-pastel-balls" bodyStyle={{ padding: '16px' }}>
<div className="flex items-start space-x-3 md:space-x-4">
{/* 全部供应商的头像组合 */}
<div className="flex-shrink-0">
@@ -210,7 +210,7 @@ const PricingVendorIntro = ({
return (
<div className='mb-4'>
<Card className="!rounded-2xl" bodyStyle={{ padding: '16px' }}>
<Card className="!rounded-2xl with-pastel-balls" bodyStyle={{ padding: '16px' }}>
<div className="flex items-start space-x-3 md:space-x-4">
{/* 供应商图标 */}
<div className="flex-shrink-0">

View File

@@ -25,7 +25,7 @@ const PricingVendorIntroSkeleton = ({
}) => {
const placeholder = (
<div className='mb-4'>
<Card className="!rounded-2xl" bodyStyle={{ padding: '16px' }}>
<Card className="!rounded-2xl with-pastel-balls" bodyStyle={{ padding: '16px' }}>
<div className="flex items-start space-x-3 md:space-x-4">
{/* 供应商图标骨架 */}
<div className="flex-shrink-0 min-w-16 h-16 rounded-2xl bg-white shadow-md flex items-center justify-center px-2">

View File

@@ -374,6 +374,7 @@
"已用额度": "Quota used",
"剩余额度": "Remaining quota",
"总额度": "Total quota",
"剩余额度/总额度": "Remaining/Total",
"智能熔断": "Smart fallback",
"当前分组为 auto会自动选择最优分组当一个组不可用时自动降级到下一个组熔断机制": "The current group is auto, it will automatically select the optimal group, and automatically downgrade to the next group when a group is unavailable (breakage mechanism)",
"过期时间": "Expiration time",
@@ -584,7 +585,7 @@
"确定是否要修复数据库一致性?": "Are you sure you want to repair database consistency?",
"进行该操作时,可能导致渠道访问错误,请仅在数据库出现问题时使用": "When performing this operation, it may cause channel access errors. Please only use it when there is a problem with the database.",
"当前没有可用的启用令牌,请确认是否有令牌处于启用状态!": "There are currently no enablement tokens available, please confirm if one is enabled!",
"令牌管理": "Token Management",
"令牌管理": "API Keys",
"使用日志": "Usage log",
"Midjourney日志": "Midjourney",
"数据看板": "Dashboard",
@@ -1789,7 +1790,7 @@
"将仅保留第一个密钥文件,其余文件将被移除,是否继续?": "Only the first key file will be retained, and the remaining files will be removed. Continue?",
"自定义模型名称": "Custom model name",
"启用全部密钥": "Enable all keys",
"以充值价格显示": "Show with recharge price",
"以充值价格显示": "Recharge price",
"美元汇率(非充值汇率,仅用于定价页面换算)": "USD exchange rate (not recharge rate, only used for pricing page conversion)",
"美元汇率": "USD exchange rate",
"隐藏操作项": "Hide actions",
@@ -1810,5 +1811,84 @@
"图片输入: {{imageRatio}}": "Image input: {{imageRatio}}",
"系统提示覆盖": "System prompt override",
"模型: {{ratio}}": "Model: {{ratio}}",
"专属倍率": "Exclusive group ratio"
"专属倍率": "Exclusive group ratio",
"模型管理": "Models",
"匹配类型": "Matching type",
"描述": "Description",
"供应商": "Vendor",
"端点": "Endpoint",
"已绑定渠道": "Bound channels",
"更新时间": "Update time",
"未配置模型": "No model configured",
"预填组管理": "Pre-filled group management",
"搜索供应商": "Search vendor",
"新增供应商": "Add vendor",
"创建新的模型": "Create new model",
"更新模型信息": "Update model information",
"请输入模型名称gpt-4": "Please enter the model name, such as: gpt-4",
"设置模型的基本信息": "Set the basic information of the model",
"名称匹配类型": "Name matching type",
"根据模型名称和匹配规则查找模型元数据,优先级:精确 > 前缀 > 后缀 > 包含": "Find model metadata based on model name and matching rules, priority: exact > prefix > suffix > contains",
"请选择名称匹配类型": "Please select the name matching type",
"请输入模型描述": "Please enter the model description",
"输入标签或使用\",\"分隔多个标签": "Enter tags or use \",\" to separate multiple tags",
"选择模型供应商": "Select model vendor",
"端点映射": "Endpoint mapping",
"可视化": "Visualization",
"手动编辑": "Manual editing",
"暂无数据,点击下方按钮添加键值对": "No data, click the button below to add key-value pairs",
"添加键值对": "Add key-value pair",
"留空则使用默认端点;支持 {path, method}": "Leave blank to use the default endpoint; supports {path, method}",
"未配置的模型列表": "Models not configured",
"个未配置模型": "models not configured",
"组列表": "Group list",
"管理模型、标签、端点等预填组": "Manage model, tag, endpoint, etc. pre-filled groups",
"新建组": "New group",
"组名": "Group name",
"项目内容": "Item content",
"创建新的预填组": "Create new pre-filled group",
"更新预填组": "Update pre-filled group",
"设置预填组的基本信息": "Set the basic information of the pre-filled group",
"请输入组名": "Please enter the group name",
"请输入组描述": "Please enter the group description",
"项目": "Item",
"输入项目名称,按回车添加": "Enter the item name, press Enter to add",
"键为端点类型,值为路径和方法对象": "The key is the endpoint type, the value is the path and method object",
"模型组": "Model group",
"标签组": "Tag group",
"端点组": "Endpoint group",
"供应商名称": "Vendor name",
"请输入供应商名称OpenAI": "Please enter the vendor name, such as: OpenAI",
"请输入供应商描述": "Please enter the vendor description",
"供应商图标": "Vendor icon",
"请输入图标名称OpenAI、Claude.Color": "Please enter the icon name, such as: OpenAI, Claude.Color",
"图标使用@lobehub/icons库查询所有可用图标 ": "The icon uses the @lobehub/icons library, query all available icons ",
"请点击我": "Please click me",
"精确": "Exact",
"前缀": "Prefix",
"后缀": "Suffix",
"包含": "Contains",
"全部供应商": "All vendors",
"筛选": "Filter",
"显示设置": "Display settings",
"可用令牌分组": "Available token groups",
"端点类型": "Endpoint type",
"全部分组": "All groups",
"全部类型": "All types",
"全部端点": "All endpoints",
"显示倍率": "Show ratio",
"表格视图": "Table view",
"模型的详细描述和基本特性": "Detailed description and basic characteristics of the model",
"API端点": "API endpoints",
"模型支持的接口端点信息": "Model supported API endpoint information",
"分组价格": "Group price",
"不同用户分组的价格信息": "Price information for different user groups",
"auto分组调用链路": "auto group call chain",
"查看所有可用的AI模型供应商包括众多知名供应商的模型。": "View all available AI model suppliers, including models from many well-known suppliers.",
"包含来自未知或未标明供应商的AI模型这些模型可能来自小型供应商或开源项目。": "Includes AI models from unknown or unmarked suppliers, which may come from small suppliers or open-source projects.",
"该供应商提供多种AI模型适用于不同的应用场景。": "This supplier provides multiple AI models, suitable for different application scenarios.",
"未知供应商": "Unknown",
"共 {{count}} 个模型": "{{count}} models",
"倍率信息": "Ratio information",
"倍率是用于系统计算不同模型的最终价格用的,如果您不理解倍率,请忽略": "The ratio is used to calculate the final price of different models in the system. If you do not understand the ratio, please ignore it."
}

View File

@@ -593,6 +593,60 @@ html:not(.dark) .blur-ball-teal {
opacity: 0.2;
}
/* ==================== 卡片马卡龙模糊球(类封装) ==================== */
/* 使用方式:给容器加上 with-pastel-balls 类即可,无需在 JSX 中插入额外节点 */
.with-pastel-balls {
position: relative;
overflow: hidden;
/* 默认变量(明亮模式) */
--pb1: #ffd1dc;
/* 粉 */
--pb2: #e5d4ff;
/* 薰衣草 */
--pb3: #d1fff6;
/* 薄荷 */
--pb4: #ffe5d9;
/* 桃 */
--pb-opacity: 0.55;
--pb-blur: 60px;
}
.with-pastel-balls::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
background:
radial-gradient(circle at -5% -10%, var(--pb1) 0%, transparent 60%),
radial-gradient(circle at 105% -10%, var(--pb2) 0%, transparent 55%),
radial-gradient(circle at 5% 110%, var(--pb3) 0%, transparent 55%),
radial-gradient(circle at 105% 110%, var(--pb4) 0%, transparent 50%);
filter: blur(var(--pb-blur));
opacity: var(--pb-opacity);
transform: translateZ(0);
}
/* 暗黑模式下更柔和的色彩和透明度 */
html.dark .with-pastel-balls {
/* 使用与明亮模式一致的“刚才那组”马卡龙色,但整体更柔和 */
--pb1: #ffd1dc;
/* 粉 */
--pb2: #e5d4ff;
/* 薰衣草 */
--pb3: #d1fff6;
/* 薄荷 */
--pb4: #ffe5d9;
/* 桃 */
--pb-opacity: 0.36;
--pb-blur: 65px;
}
/* 暗黑模式下用更柔和的混合模式避免突兀的高亮 */
html.dark .with-pastel-balls::before {
mix-blend-mode: screen;
}
/* ==================== 表格卡片滚动设置 ==================== */
.table-scroll-card {
display: flex;