index.tsx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. "use client";
  2. import { Skeleton } from "@pythnetwork/component-library/Skeleton";
  3. import {
  4. GridList,
  5. GridListItem,
  6. } from "@pythnetwork/component-library/unstyled/GridList";
  7. import clsx from "clsx";
  8. import type { ComponentProps, ReactNode } from "react";
  9. import styles from "./index.module.scss";
  10. type Props<T extends string> = ComponentProps<typeof GridList<RowConfig<T>>> & {
  11. headerLoadingSkeleton?: ReactNode | undefined;
  12. label: string;
  13. fields: ({
  14. id: T;
  15. name: ReactNode;
  16. } & (
  17. | { loadingSkeleton?: ReactNode | undefined }
  18. | { loadingSkeletonWidth?: number | undefined }
  19. ))[];
  20. } & (
  21. | {
  22. isLoading: true;
  23. rows?: RowConfig<T>[] | undefined;
  24. }
  25. | {
  26. isLoading?: false | undefined;
  27. rows: RowConfig<T>[];
  28. }
  29. );
  30. type RowConfig<T extends string> = {
  31. id: string | number;
  32. data: Record<T, ReactNode>;
  33. header?: ReactNode | undefined;
  34. href?: string;
  35. textValue: string;
  36. };
  37. export const EntityList = <T extends string>({
  38. fields,
  39. isLoading,
  40. rows,
  41. headerLoadingSkeleton,
  42. className,
  43. label,
  44. ...props
  45. }: Props<T>) => (
  46. <GridList
  47. className={clsx(styles.entityList, className)}
  48. items={isLoading ? [] : rows}
  49. aria-label={label}
  50. {...props}
  51. >
  52. {isLoading ? (
  53. <GridListItem className={styles.entityItem ?? ""} textValue="Loading">
  54. <div className={styles.itemHeader}>{headerLoadingSkeleton}</div>
  55. <dl className={styles.itemDetails}>
  56. {fields.map((field) => (
  57. <div key={field.id} className={styles.itemDetailsItem}>
  58. <dt>{field.name}</dt>
  59. <dd>
  60. {"loadingSkeleton" in field ? (
  61. field.loadingSkeleton
  62. ) : (
  63. <Skeleton
  64. width={
  65. "loadingSkeletonWidth" in field
  66. ? field.loadingSkeletonWidth
  67. : 20
  68. }
  69. />
  70. )}
  71. </dd>
  72. </div>
  73. ))}
  74. </dl>
  75. </GridListItem>
  76. ) : (
  77. ({ data, header, ...props }) => (
  78. <GridListItem className={styles.entityItem ?? ""} {...props}>
  79. {header && <div className={styles.itemHeader}>{header}</div>}
  80. <dl className={styles.itemDetails}>
  81. {fields.map((field) => (
  82. <div key={field.id} className={styles.itemDetailsItem}>
  83. <dt>{field.name}</dt>
  84. <dd>{data[field.id]}</dd>
  85. </div>
  86. ))}
  87. </dl>
  88. </GridListItem>
  89. )
  90. )}
  91. </GridList>
  92. );