You've already forked DataMate
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:
@@ -181,7 +181,7 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
|
||||
{data.map((item) => (
|
||||
<div
|
||||
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
|
||||
@@ -194,9 +194,22 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
{item?.icon && (
|
||||
<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 className="flex-1 min-w-0">
|
||||
@@ -236,7 +249,7 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
|
||||
<TagsRenderer tags={item?.tags || []} />
|
||||
|
||||
{/* 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}>
|
||||
{item?.description}
|
||||
</Tooltip>
|
||||
@@ -258,8 +271,9 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex items-center justify-between pt-3 border-t border-t-gray-200">
|
||||
{/* Divider & Actions */}
|
||||
<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="flex items-center gap-1">
|
||||
<ClockCircleOutlined className="w-4 h-4" />{" "}
|
||||
|
||||
@@ -49,9 +49,14 @@ function DetailHeader<T>({
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-4 flex-1">
|
||||
<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" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -56,8 +56,19 @@ export function ListView({ operators = [], pagination, operations }) {
|
||||
>
|
||||
<List.Item.Meta
|
||||
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 className="w-8 h-8 text-white">{operator?.icon}</div>
|
||||
<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>
|
||||
}
|
||||
title={
|
||||
|
||||
@@ -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 { 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", // 文本算子背景色
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
icon: <Code className="w-full h-full" />,
|
||||
iconColor: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export const mapOperator = (op: OperatorI) => {
|
||||
const visual = getOperatorVisual(op);
|
||||
|
||||
return {
|
||||
...op,
|
||||
icon: <Code className="w-full h-full" />,
|
||||
icon: visual.icon,
|
||||
iconColor: visual.iconColor,
|
||||
createdAt: formatDateTime(op?.createdAt) || "--",
|
||||
updatedAt: formatDateTime(op?.updatedAt) || formatDateTime(op?.createdAt) || "--",
|
||||
updatedAt:
|
||||
formatDateTime(op?.updatedAt) ||
|
||||
formatDateTime(op?.createdAt) ||
|
||||
"--",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface OperatorI {
|
||||
inputs: string;
|
||||
outputs: string;
|
||||
icon: React.ReactNode;
|
||||
iconColor?: string; // 图标背景色,用于区分不同类型算子
|
||||
description: string;
|
||||
tags: string[];
|
||||
isStar?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user