npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@botply-kit/detail

v3.1.4

Published

A detail package for botply

Readme

通用详情组件

一套通用的详情页面组件,提供统一的布局和样式,方便在不同页面复用。

组件列表

主容器组件

  • DetailLayout - 详情页面完整布局(包含面包屑导航和页面标题)
  • Detail - 详情内容容器
  • DetailSkeleton - 加载状态骨架屏
  • DetailError - 错误状态组件

详情项组件

  • StringItem - 文本显示项
  • LinkItem - 链接显示项
  • DateItem - 日期显示项
  • TagItem - 标签显示项
  • TextareaItem - 多行文本显示项
  • ActionItem - 操作按钮项
  • TableItem - 表格显示项
  • CustomItem - 自定义内容项

使用示例

完整页面布局

import {
  ActionItem,
  DateItem,
  Detail,
  DetailError,
  DetailLayout,
  DetailSkeleton,
  LinkItem,
  StringItem,
  TableItem,
  TagItem,
  TextareaItem,
} from "@/components/detail"

function UserDetail() {
  const { data, isPending, isError, refetch } = useUserDetail(id)
  const navigate = useNavigate()
  const router = useRouter()
  const canGoBack = useCanGoBack()

  const goUserList = () => {
    if (canGoBack) {
      router.history.back()
    } else {
      router.navigate({ to: "/users" })
    }
  }

  const breadcrumbs = [
    {
      label: "用户列表",
      onClick: goUserList,
    },
    {
      label: "用户详情",
    },
  ]

  if (isPending) {
    return (
      <DetailLayout
        title="用户详情"
        description="查看用户的详细信息"
        breadcrumbs={breadcrumbs}
      >
        <DetailSkeleton itemCount={6} />
      </DetailLayout>
    )
  }

  if (isError) {
    return (
      <DetailLayout
        title="用户详情"
        description="查看用户的详细信息"
        breadcrumbs={breadcrumbs}
      >
        <DetailError onRetry={() => refetch()} />
      </DetailLayout>
    )
  }

  return (
    <DetailLayout
      title="用户详情"
      description="查看用户的详细信息"
      breadcrumbs={breadcrumbs}
    >
      <Detail title="基本信息">
        <StringItem label="用户名" value={data.username} />
        <StringItem label="邮箱" value={data.email} />
        <LinkItem label="个人网站" value={data.website} />
        <DateItem label="注册时间" value={data.createdAt} />
        <TagItem label="标签" value={data.tags} />
        <TextareaItem label="个人简介" value={data.bio} />
        <ActionItem
          label="操作"
          actions={[
            {
              label: "编辑",
              variant: "default",
              onClick: () => navigate("/users/edit"),
            },
            {
              label: "删除",
              variant: "destructive",
              onClick: () => handleDelete(),
            },
          ]}
        />
      </Detail>
    </DetailLayout>
  )
}

基本用法(不含页面布局)

<Detail title="用户详情" description="查看用户的详细信息">
  <StringItem label="用户名" value={data.username} />
  <StringItem label="邮箱" value={data.email} />
  <LinkItem label="个人网站" value={data.website} />
  <DateItem label="注册时间" value={data.createdAt} />
  <TagItem label="标签" value={data.tags} />
  <TextareaItem label="个人简介" value={data.bio} />
</Detail>

自定义内容

<DetailLayout title="产品详情" breadcrumbs={breadcrumbs}>
  <Detail title="产品信息">
    <StringItem label="产品名称" value={data.name} />
    <CustomItem label="价格">
      <div className="flex items-center gap-2">
        <span className="text-2xl font-bold text-green-600">¥{data.price}</span>
        <Badge variant="secondary">限时优惠</Badge>
      </div>
    </CustomItem>
    <TableItem label="规格参数" component={<SpecTable />} />
  </Detail>
</DetailLayout>

组件属性

DetailLayout

| 属性 | 类型 | 默认值 | 说明 | | ----------- | -------------------- | ------ | -------------- | | title | string | - | 页面标题 | | description | string | - | 页面描述 | | breadcrumbs | BreadcrumbItemType[] | - | 面包屑导航配置 | | children | ReactNode | - | 子组件 |

BreadcrumbItemType

| 属性 | 类型 | 默认值 | 说明 | | ------- | ---------- | ------ | ---------------- | | label | string | - | 面包屑文本 | | href | string | - | 链接地址(可选) | | onClick | () => void | - | 点击事件(可选) |

Detail

| 属性 | 类型 | 默认值 | 说明 | | ----------- | --------- | ------ | ------------ | | title | string | - | 详情页面标题 | | description | string | - | 详情页面描述 | | children | ReactNode | - | 子组件 | | className | string | - | 自定义样式类 |

DetailSkeleton

| 属性 | 类型 | 默认值 | 说明 | | --------- | ------ | ---------- | -------------- | | title | string | "详情信息" | 骨架屏标题 | | itemCount | number | 6 | 骨架屏项目数量 |

DetailError

| 属性 | 类型 | 默认值 | 说明 | | ------- | ---------- | ------------------------------------ | ------------ | | title | string | "加载失败" | 错误标题 | | message | string | "获取详情信息时发生错误,请稍后重试" | 错误消息 | | onRetry | () => void | - | 重试回调函数 |

StringItem

| 属性 | 类型 | 默认值 | 说明 | | ----------- | -------------- | ------ | ---------- | | label | string | - | 字段标签 | | value | string | null | - | 显示值 | | placeholder | string | "-" | 空值占位符 |

LinkItem

| 属性 | 类型 | 默认值 | 说明 | | ----------- | -------------- | ------ | ---------- | | label | string | - | 字段标签 | | value | string | null | - | 链接地址 | | placeholder | string | "-" | 空值占位符 |

DateItem

| 属性 | 类型 | 默认值 | 说明 | | ----------- | ---------------------- | --------------------- | ---------- | | label | string | - | 字段标签 | | value | string | Date | null | - | 日期值 | | placeholder | string | "-" | 空值占位符 | | formatStr | string | "yyyy-MM-dd HH:mm:ss" | 日期格式 |

TagItem

| 属性 | 类型 | 默认值 | 说明 | | ----------- | ---------------- | -------- | ---------- | | label | string | - | 字段标签 | | value | string[] | null | - | 标签数组 | | placeholder | string | "无标签" | 空值占位符 |

ActionItem

| 属性 | 类型 | 默认值 | 说明 | | ------- | ------------------ | ------ | ------------ | | label | string | - | 字段标签 | | actions | ActionItemAction[] | - | 操作按钮配置 |

ActionItemAction

| 属性 | 类型 | 默认值 | 说明 | | -------- | ------------- | --------- | -------- | | label | string | - | 按钮文本 | | onClick | () => void | - | 点击事件 | | variant | ButtonVariant | "outline" | 按钮样式 | | disabled | boolean | false | 是否禁用 |

设计特点

  1. 完整布局 - DetailLayout 提供与创建页面一致的布局结构
  2. 面包屑导航 - 支持灵活的面包屑配置,提升用户体验
  3. 统一风格 - 与表单页面保持一致的卡片设计风格
  4. 响应式设计 - 采用网格布局,标签和内容分离
  5. 类型安全 - 完整的 TypeScript 类型定义
  6. 状态处理 - 内置加载和错误状态,提升用户体验
  7. 易于复用 - 简洁的 API 设计,可在其他页面快速使用

最佳实践

  1. 使用 DetailLayout - 对于完整的详情页面,推荐使用 DetailLayout 组件
  2. 面包屑导航 - 配置合理的面包屑导航,提升用户体验
  3. 状态处理 - 始终处理加载和错误状态
  4. 操作按钮 - 合理配置操作按钮的样式和权限
  5. 内容分组 - 使用多个 Detail 组件对内容进行逻辑分组