过滤卡片组件

一个基于React和TypeScript构建的交互式、可访问的过滤卡片组件,具有语义化颜色、平滑状态过渡、涟漪效果和完整的键盘/屏幕阅读器支持。

  • by orbitastudio
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 orbitastudio/Zededa-MCP-explorations

使用说明

过滤卡组件

一个使用React和TypeScript构建的交互式、可访问的过滤卡组件,符合Figma的设计规范。具有语义颜色、平滑的状态转换、波纹效果和全键盘/屏幕阅读器支持。

🎯 特性

  • ✅ 三个互动州:默认、悬停和选定
  • ✅ 语义色彩:严重(红色)、警报(黄色)、信息(蓝色)、成功(绿色)、通知(橙色)
  • ✅ 涟漪效应:材质设计灵感点击动画
  • ✅ 完全无障碍:键盘导航、屏幕阅读器支持、ARIA标签
  • ✅ 移动友好:触摸目标符合无障碍指南(最小44x44px)
  • ✅ 响应式设计:在移动和桌面上无缝工作
  • ✅ 类型安全:使用TypeScript构建,提供更好的开发人员体验
  • ✅ CSS模块:限定样式以防止冲突

📸 预览

该组件包括五个语义变体:

类型 颜色 用例
关键的 #ff7f7f 需要立即关注的紧急问题
警报 #ffd86e 需要审查的警告或问题
信息 #6775e4 信息更新或新项目
成功 #29cf8d 积极指标或健康状况
通知 #ffa16e 重要通知或需要注意的事项

州

  • 默认状态背景 #2c2826
  • 悬停状态背景 #332f2b (鼠标悬停时)
  • 被选定状态背景 #332f2b 带有蓝色边框轮廓(单击后仍然存在)
  • 涟漪效应:点击时出现白色波纹动画(持续时间600ms)

🚀 快速开始

安装

  1. 克隆此存储库或复制组件文件:

    • FilterCard.tsx
    • FilterCard.module.css
  2. 安装依赖项:

npm install
  1. 运行开发服务器:
npm run dev
  1. 打开浏览器 http://localhost:3000

基本用法

import React, { useState } from 'react';
import FilterCard from './FilterCard';

function App() {
  const [selected, setSelected] = useState(false);

  return (
    <FilterCard
      type="critical"
      title="4 critical alerts"
      subtitle="Review nodes with critical alerts"
      selected={selected}
      onClick={() => setSelected(!selected)}
    />
  );
}

📚 API 参考

过滤卡属性

道具 类型 必填 默认 描述
type 'critical' | 'alert' | 'info' | 'success' | 'notice' ✅ 是 - 卡片的语义类型
title string ✅ 是 - 主标题文本
subtitle string ✅ 是 - 字幕/描述文本
selected boolean ❌ 没有 false 当前是否选中该卡
onClick () => void ❌ 无 - 卡片点击时的回拨功能
className string ❌ 没有 '' 其他CSS类名
testId string ❌ 无 - 用于测试的测试ID

类型定义

export type FilterCardType = 'critical' | 'alert' | 'info' | 'success' | 'notice';

export interface FilterCardProps {
  type: FilterCardType;
  title: string;
  subtitle: string;
  selected?: boolean;
  onClick?: () => void;
  className?: string;
  testId?: string;
}

🎨 设计标记

颜色

/* Background Colors */
--card-bg-default: #2c2826;
--card-bg-hover: #332f2b;
--card-bg-selected: #332f2b;

/* Text Colors */
--text-primary: #fffcfa;
--text-secondary: #a7a7a7;

/* Semantic Colors */
--color-critical: #ff7f7f;
--color-alert: #ffd86e;
--color-info: #6775e4;
--color-success: #29cf8d;
--color-notice: #ffa16e;

/* Border & Outline */
--border-radius-card: 8px;
--border-radius-icon: 4px;
--outline-color: #6775e4;

排版

  • 字体家族:DM Sans
  • 标题:16px,行高20px,重量400
  • 字幕:14px,行高16px,重量400

间距

  • 卡片填充:16像素
  • 图标填充:12像素
  • 内容差距:12像素
  • 文本间隙:4px

♿ 辅助功能

键盘导航

  • 选项卡:在卡片之间导航
  • 进入 或 太空:激活/选择聚焦卡
  • 焦点指示器:通过键盘聚焦卡片时出现蓝色轮廓

屏幕阅读器支持

  • 卡片包括适当的ARIA标签(aria-label, aria-pressed)
  • 角色设置为 button 为了获得正确的语义
  • 向屏幕阅读器宣布状态更改

附加功能

  • 高对比度模式:在高对比度模式下增强边框
  • 减少运动:尊重 prefers-reduced-motion 偏好
  • 触摸目标:移动设备上的最小44x44px触摸目标
  • 颜色对比度:符合WCAG AA标准

📱 响应式设计

该组件可适应不同的屏幕尺寸:

  • 桌面:固定宽度(312px)
  • 移动:适应集装箱宽度
  • 触摸设备:增强触摸目标

🧪 测试

运行类型检查:

npm run type-check

运行linting:

npm run lint

使用数据属性进行测试

该组件公开数据属性以便于测试:

<FilterCard
  testId="my-card"
  type="critical"
  // ... other props
/>

测试中的访问权限:

const card = screen.getByTestId('my-card');
expect(card).toHaveAttribute('data-type', 'critical');
expect(card).toHaveAttribute('data-selected', 'true');

🎯 示例用例

仪表板警报

<FilterCard
  type="critical"
  title="4 critical alerts"
  subtitle="Review nodes with critical alerts"
  onClick={() => navigateToAlerts()}
/>

状态概述

<FilterCard
  type="success"
  title="95% CPU health"
  subtitle="Click to improve CPU health"
  onClick={() => showHealthDetails()}
/>

信息卡

<FilterCard
  type="info"
  title="3 new nodes"
  subtitle="Last week"
  onClick={() => showNewNodes()}
/>

警告通知

<FilterCard
  type="alert"
  title="60 offline nodes"
  subtitle="For the last week"
  onClick={() => showOfflineNodes()}
/>

通知卡

<FilterCard
  type="notice"
  title="60 offline nodes"
  subtitle="For the last week"
  onClick={() => showOfflineNodes()}
/>

🛠️ 定制

自定义样式

您可以通过传递自定义类名来扩展组件的样式:

<FilterCard
  type="info"
  title="Custom Card"
  subtitle="With custom styling"
  className="my-custom-card"
/>

然后在CSS中:

.my-custom-card {
  width: 400px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

受控与不受控

该组件可以在两种模式下工作:

受控的 (推荐):

const [selectedId, setSelectedId] = useState<number | null>(null);

<FilterCard
  selected={selectedId === 1}
  onClick={() => setSelectedId(selectedId === 1 ? null : 1)}
/>

失控的:

<FilterCard
  onClick={() => console.log('Card clicked')}
/>

📦 构建

生产建设:

npm run build

预览生产版本:

npm run preview

🤝 贡献

欢迎投稿!请按照以下步骤操作:

  1. 分叉存储库
  2. 创建要素分支(git checkout -b feature/amazing-feature)
  3. 提交您的更改(git commit -m 'Add amazing feature')
  4. 推到分支(git push origin feature/amazing-feature)
  5. 打开拉取请求

📄 许可证

此项目根据MIT许可证获得许可-有关详细信息,请参阅许可证文件。

🙏 致谢

  • Figma的设计规范
  • 受材料设计启发的图标
  • 使用React和TypeScript构建
  • 使用CSS模块进行样式设置

📞 支持

如果您遇到任何问题或有疑问:

  1. 检查 问题 页
  2. 创建一个带有详细描述的新问题
  3. 包括代码示例和屏幕截图(如适用)

内置于❤️ 使用React+TypeScript