index.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import Generic from "cryptocurrency-icons/svg/color/generic.svg";
  2. import { Fragment } from "react";
  3. import { z } from "zod";
  4. import { columns } from "./columns";
  5. import { Price } from "./prices";
  6. import { Results } from "./results";
  7. import { getIcon } from "../../icons";
  8. import { client } from "../../pyth";
  9. export const PriceFeeds = async () => {
  10. const priceFeeds = await getPriceFeeds();
  11. return (
  12. <Results
  13. label="Price Feeds"
  14. columns={columns}
  15. priceFeeds={priceFeeds.map(({ symbol, product }) => ({
  16. symbol,
  17. key: product.price_account,
  18. displaySymbol: product.display_symbol,
  19. data: {
  20. asset: <AssetName>{product.display_symbol}</AssetName>,
  21. assetType: <AssetType>{product.asset_type}</AssetType>,
  22. price: <Price account={product.price_account} />,
  23. uptime: 43,
  24. deviation: 56,
  25. staleness: 46,
  26. },
  27. }))}
  28. />
  29. );
  30. };
  31. const AssetName = ({ children }: { children: string }) => {
  32. const [firstPart, ...parts] = children.split("/");
  33. const Icon = firstPart ? (getIcon(firstPart) ?? Generic) : Generic;
  34. return (
  35. <div className="flex flex-row gap-3">
  36. <Icon className="size-6" width="100%" height="100%" viewBox="0 0 32 32" />
  37. <div className="flex flex-row items-center gap-1">
  38. <span className="font-medium">{firstPart}</span>
  39. {parts.map((part, i) => (
  40. <Fragment key={i}>
  41. <span className="font-light text-stone-600 dark:text-steel-400">
  42. /
  43. </span>
  44. <span className="opacity-60">{part}</span>
  45. </Fragment>
  46. ))}
  47. </div>
  48. </div>
  49. );
  50. };
  51. const AssetType = ({ children }: { children: string }) => (
  52. <span className="inline-block rounded-3xl border border-steel-900 px-2 text-[0.625rem] uppercase leading-4 text-steel-900 dark:border-steel-50 dark:text-steel-50">
  53. {children}
  54. </span>
  55. );
  56. const getPriceFeeds = async () => {
  57. const data = await client.getData();
  58. return priceFeedsSchema.parse(
  59. data.symbols.map((symbol) => ({
  60. symbol,
  61. product: data.productFromSymbol.get(symbol),
  62. })),
  63. );
  64. };
  65. const priceFeedsSchema = z.array(
  66. z.object({
  67. symbol: z.string(),
  68. product: z.object({
  69. display_symbol: z.string(),
  70. asset_type: z.string(),
  71. price_account: z.string(),
  72. }),
  73. }),
  74. );