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) => (
|
{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" />{" "}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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={
|
||||||
|
|||||||
@@ -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) ||
|
||||||
|
"--",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user