polish(operator cards): improve icon color distinction and subtle UI … (#217)

polish(operator cards): improve icon color distinction and subtle UI details
This commit is contained in:
Kecheng Sha
2025-12-31 10:54:34 +08:00
committed by GitHub
parent f183b9f2f3
commit 01e1c6c7e9
5 changed files with 679 additions and 601 deletions

View File

@@ -181,7 +181,7 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
{data.map((item) => ( {data.map((item) => (
<div <div
key={item.id} key={item.id}
className="border-card p-4 bg-white hover:shadow-lg transition-shadow duration-200" className="border-card p-4 bg-white duration-200 transition-shadow transition-transform hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,0,0,0.06)]"
> >
<div className="flex flex-col space-y-4 h-full"> <div className="flex flex-col space-y-4 h-full">
<div <div
@@ -194,9 +194,22 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
<div className="flex items-center gap-3 min-w-0"> <div className="flex items-center gap-3 min-w-0">
{item?.icon && ( {item?.icon && (
<div <div
className={`flex-shrink-0 w-12 h-12 bg-gradient-to-br from-sky-300 to-blue-500 text-white rounded-lg flex items-center justify-center`} className={`flex-shrink-0 w-12 h-12 rounded-lg flex items-center justify-center ${
item?.iconColor
? ""
: "bg-gradient-to-br from-sky-300 to-blue-500 text-white"
}`}
style={{
...(item?.iconColor
? { backgroundColor: item.iconColor }
: {}),
backgroundImage:
"linear-gradient(180deg, rgba(255,255,255,0.35), rgba(255,255,255,0.05))",
boxShadow:
"inset 0 0 0 1px rgba(255,255,255,0.25)",
}}
> >
<div className="w-6 h-6 text-gray-50">{item?.icon}</div> <div className="w-[2.1rem] h-[2.1rem] text-gray-50">{item?.icon}</div>
</div> </div>
)} )}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
@@ -236,7 +249,7 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
<TagsRenderer tags={item?.tags || []} /> <TagsRenderer tags={item?.tags || []} />
{/* Description */} {/* Description */}
<p className="text-gray-600 text-xs text-ellipsis overflow-hidden whitespace-nowrap text-xs line-clamp-2 mt-2"> <p className="text-gray-400 text-xs text-ellipsis overflow-hidden whitespace-nowrap text-xs line-clamp-2 mt-2">
<Tooltip title={item?.description}> <Tooltip title={item?.description}>
{item?.description} {item?.description}
</Tooltip> </Tooltip>
@@ -258,8 +271,9 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
</div> </div>
</div> </div>
{/* Actions */} {/* Divider & Actions */}
<div className="flex items-center justify-between pt-3 border-t border-t-gray-200"> <div className="w-2/3 border-t border-t-gray-200 mt-2" />
<div className="flex items-center justify-between pt-3">
<div className=" text-gray-500 text-right"> <div className=" text-gray-500 text-right">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<ClockCircleOutlined className="w-4 h-4" />{" "} <ClockCircleOutlined className="w-4 h-4" />{" "}

View File

@@ -49,9 +49,14 @@ function DetailHeader<T>({
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex items-start gap-4 flex-1"> <div className="flex items-start gap-4 flex-1">
<div <div
className={`w-16 h-16 text-white rounded-lg flex-center shadow-lg bg-gradient-to-br from-sky-300 to-blue-500 text-white`} className={`w-16 h-16 text-white rounded-lg flex-center shadow-lg ${
(data as any)?.iconColor
? ""
: "bg-gradient-to-br from-sky-300 to-blue-500 text-white"
}`}
style={(data as any)?.iconColor ? { backgroundColor: (data as any).iconColor } : undefined}
> >
{<div className="w-8 h-8 text-gray-50">{data?.icon}</div> || ( {<div className="w-[2.8rem] h-[2.8rem] text-gray-50">{(data as any)?.icon}</div> || (
<Database className="w-8 h-8 text-white" /> <Database className="w-8 h-8 text-white" />
)} )}
</div> </div>

View File

@@ -56,8 +56,19 @@ export function ListView({ operators = [], pagination, operations }) {
> >
<List.Item.Meta <List.Item.Meta
avatar={ avatar={
<div className="w-12 h-12 bg-gradient-to-br from-sky-300 to-blue-500 rounded-lg flex items-center justify-center"> <div
<div className="w-8 h-8 text-white">{operator?.icon}</div> className={`w-12 h-12 rounded-lg flex items-center justify-center ${
operator?.iconColor
? ""
: "bg-gradient-to-br from-sky-300 to-blue-500"
}`}
style={
operator?.iconColor
? { backgroundColor: operator.iconColor }
: undefined
}
>
<div className="w-[2.8rem] h-[2.8rem] text-white">{operator?.icon}</div>
</div> </div>
} }
title={ title={

View File

@@ -1,12 +1,59 @@
import { Code } from "lucide-react"; import React from "react";
import { Code, FileSliders, Image } from "lucide-react";
import { OperatorI } from "./operator.model"; import { OperatorI } from "./operator.model";
import {formatDateTime} from "@/utils/unit.ts"; import { formatDateTime } from "@/utils/unit.ts";
const getOperatorVisual = (
op: OperatorI
): { icon: React.ReactNode; iconColor?: string } => {
const type = (op?.type || "").toLowerCase();
const categories = (op?.categories || []).map((c) => (c || "").toLowerCase());
const inputs = (op?.inputs || "").toLowerCase();
const outputs = (op?.outputs || "").toLowerCase();
const isImageOp =
["image", "图像", "图像类"].includes(type) ||
categories.some((c) => c.includes("image") || c.includes("图像")) ||
inputs.includes("image") ||
outputs.includes("image");
const isTextOp =
["text", "文本", "文本类"].includes(type) ||
categories.some((c) => c.includes("text") || c.includes("文本")) ||
inputs.includes("text") ||
outputs.includes("text");
if (isImageOp) {
return {
icon: <Image className="w-full h-full" />,
iconColor: "#38BDF8", // 图像算子背景色
};
}
if (isTextOp) {
return {
icon: <FileSliders className="w-full h-full" />,
iconColor: "#A78BFA", // 文本算子背景色
};
}
export const mapOperator = (op: OperatorI) => {
return { return {
...op,
icon: <Code className="w-full h-full" />, icon: <Code className="w-full h-full" />,
createdAt: formatDateTime(op?.createdAt) || "--", iconColor: undefined,
updatedAt: formatDateTime(op?.updatedAt) || formatDateTime(op?.createdAt) || "--", };
};
export const mapOperator = (op: OperatorI) => {
const visual = getOperatorVisual(op);
return {
...op,
icon: visual.icon,
iconColor: visual.iconColor,
createdAt: formatDateTime(op?.createdAt) || "--",
updatedAt:
formatDateTime(op?.updatedAt) ||
formatDateTime(op?.createdAt) ||
"--",
}; };
}; };

View File

@@ -29,6 +29,7 @@ export interface OperatorI {
inputs: string; inputs: string;
outputs: string; outputs: string;
icon: React.ReactNode; icon: React.ReactNode;
iconColor?: string; // 图标背景色,用于区分不同类型算子
description: string; description: string;
tags: string[]; tags: string[];
isStar?: boolean; isStar?: boolean;