= {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ [P in keyof T as Exclude]: T[P];
+};
diff --git a/apps/entropy-explorer/stylelint.config.js b/apps/entropy-explorer/stylelint.config.js
new file mode 100644
index 0000000000..d1a0ed4fc6
--- /dev/null
+++ b/apps/entropy-explorer/stylelint.config.js
@@ -0,0 +1,21 @@
+import standardScss from "stylelint-config-standard-scss";
+
+const config = {
+ extends: standardScss,
+ rules: {
+ "selector-class-pattern": [
+ "^[a-z][a-zA-Z0-9]+$",
+ {
+ message: (selector) =>
+ `Expected class selector "${selector}" to be camel-case`,
+ },
+ ],
+ "selector-pseudo-class-no-unknown": [
+ true,
+ {
+ ignorePseudoClasses: ["global", "export"],
+ },
+ ],
+ },
+};
+export default config;
diff --git a/apps/entropy-explorer/svg.d.ts b/apps/entropy-explorer/svg.d.ts
new file mode 100644
index 0000000000..41a3172a52
--- /dev/null
+++ b/apps/entropy-explorer/svg.d.ts
@@ -0,0 +1,6 @@
+declare module "*.svg" {
+ import type { ReactElement, SVGProps } from "react";
+
+ const content: (props: SVGProps) => ReactElement;
+ export default content;
+}
diff --git a/apps/entropy-explorer/tsconfig.json b/apps/entropy-explorer/tsconfig.json
new file mode 100644
index 0000000000..dfd9bf96d0
--- /dev/null
+++ b/apps/entropy-explorer/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "@cprussin/tsconfig/nextjs.json",
+ "include": ["svg.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/apps/entropy-explorer/turbo.json b/apps/entropy-explorer/turbo.json
new file mode 100644
index 0000000000..5c225020e2
--- /dev/null
+++ b/apps/entropy-explorer/turbo.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "https://turbo.build/schema.json",
+ "extends": ["//"],
+ "tasks": {
+ "build:vercel": {
+ "env": [
+ "VERCEL_ENV",
+ "GOOGLE_ANALYTICS_ID",
+ "AMPLITUDE_API_KEY",
+ "DISABLE_ACCESSIBILITY_REPORTING"
+ ]
+ },
+ "fix:lint": {
+ "dependsOn": [
+ "//#install:modules",
+ "fix:lint:eslint",
+ "fix:lint:stylelint"
+ ]
+ },
+ "fix:lint:eslint": {
+ "dependsOn": ["//#install:modules", "^build"],
+ "cache": false
+ },
+ "fix:lint:stylelint": {
+ "dependsOn": ["//#install:modules"],
+ "cache": false
+ },
+ "start:prod": {
+ "dependsOn": ["//#install:modules", "build:vercel"]
+ },
+ "test:lint": {
+ "dependsOn": ["test:lint:eslint", "test:lint:stylelint"]
+ },
+ "test:lint:eslint": {
+ "dependsOn": ["//#install:modules", "^build"]
+ },
+ "test:lint:stylelint": {
+ "dependsOn": ["//#install:modules"]
+ }
+ }
+}
diff --git a/apps/entropy-explorer/vercel.json b/apps/entropy-explorer/vercel.json
new file mode 100644
index 0000000000..e536ad7f0c
--- /dev/null
+++ b/apps/entropy-explorer/vercel.json
@@ -0,0 +1,5 @@
+{
+ "$schema": "https://openapi.vercel.sh/vercel.json",
+ "ignoreCommand": "../../vercel-ignore.sh",
+ "buildCommand": "turbo run build:vercel --filter @pythnetwork/entropy-explorer"
+}
diff --git a/apps/insights/src/app/error.ts b/apps/insights/src/app/error.ts
index 8143974ca0..4129c5ca5c 100644
--- a/apps/insights/src/app/error.ts
+++ b/apps/insights/src/app/error.ts
@@ -1,3 +1,3 @@
"use client";
-export { Error as default } from "../components/Error";
+export { ErrorPage as default } from "@pythnetwork/component-library/ErrorPage";
diff --git a/apps/insights/src/app/global-error.tsx b/apps/insights/src/app/global-error.tsx
index 535e194876..8479e0d073 100644
--- a/apps/insights/src/app/global-error.tsx
+++ b/apps/insights/src/app/global-error.tsx
@@ -1,15 +1,14 @@
"use client";
+import { ErrorPage } from "@pythnetwork/component-library/ErrorPage";
import { LoggerProvider } from "@pythnetwork/component-library/useLogger";
import type { ComponentProps } from "react";
-import { Error } from "../components/Error";
-
-const GlobalError = (props: ComponentProps) => (
+const GlobalError = (props: ComponentProps) => (
-
+
diff --git a/apps/insights/src/app/not-found.ts b/apps/insights/src/app/not-found.ts
index aacfcb28d4..3053e90df1 100644
--- a/apps/insights/src/app/not-found.ts
+++ b/apps/insights/src/app/not-found.ts
@@ -1 +1 @@
-export { NotFound as default } from "../components/NotFound";
+export { NotFoundPage as default } from "@pythnetwork/component-library/NotFoundPage";
diff --git a/apps/insights/src/app/price-feeds/[slug]/error.ts b/apps/insights/src/app/price-feeds/[slug]/error.ts
index 4f357cc1ba..4129c5ca5c 100644
--- a/apps/insights/src/app/price-feeds/[slug]/error.ts
+++ b/apps/insights/src/app/price-feeds/[slug]/error.ts
@@ -1,3 +1,3 @@
"use client";
-export { Error as default } from "../../../components/Error";
+export { ErrorPage as default } from "@pythnetwork/component-library/ErrorPage";
diff --git a/apps/insights/src/app/publishers/[cluster]/[key]/error.ts b/apps/insights/src/app/publishers/[cluster]/[key]/error.ts
index 4bd19b42bc..4129c5ca5c 100644
--- a/apps/insights/src/app/publishers/[cluster]/[key]/error.ts
+++ b/apps/insights/src/app/publishers/[cluster]/[key]/error.ts
@@ -1,3 +1,3 @@
"use client";
-export { Error as default } from "../../../../components/Error";
+export { ErrorPage as default } from "@pythnetwork/component-library/ErrorPage";
diff --git a/apps/insights/src/components/FeedKey/index.tsx b/apps/insights/src/components/FeedKey/index.tsx
index 0f253e3dfe..f139ae8c7d 100644
--- a/apps/insights/src/components/FeedKey/index.tsx
+++ b/apps/insights/src/components/FeedKey/index.tsx
@@ -1,8 +1,8 @@
+import { CopyButton } from "@pythnetwork/component-library/CopyButton";
import type { ComponentProps } from "react";
import { useMemo } from "react";
import { toHex, truncateHex } from "../../hex";
-import { CopyButton } from "../CopyButton";
type OwnProps = {
feedKey: string;
diff --git a/apps/insights/src/components/PriceComponentDrawer/index.module.scss b/apps/insights/src/components/PriceComponentDrawer/index.module.scss
index 38927f20f9..dbcc1e2b65 100644
--- a/apps/insights/src/components/PriceComponentDrawer/index.module.scss
+++ b/apps/insights/src/components/PriceComponentDrawer/index.module.scss
@@ -33,7 +33,7 @@
display: none;
@include theme.breakpoint("md") {
- display: inline flow-root;
+ display: inline-flex;
}
}
diff --git a/apps/insights/src/components/PriceComponentDrawer/index.tsx b/apps/insights/src/components/PriceComponentDrawer/index.tsx
index 990b1aa622..1861f92c6d 100644
--- a/apps/insights/src/components/PriceComponentDrawer/index.tsx
+++ b/apps/insights/src/components/PriceComponentDrawer/index.tsx
@@ -9,6 +9,7 @@ import { Spinner } from "@pythnetwork/component-library/Spinner";
import { StatCard } from "@pythnetwork/component-library/StatCard";
import { Table } from "@pythnetwork/component-library/Table";
import type { Button as UnstyledButton } from "@pythnetwork/component-library/unstyled/Button";
+import { StateType, useData } from "@pythnetwork/component-library/useData";
import { useDrawer } from "@pythnetwork/component-library/useDrawer";
import { useLogger } from "@pythnetwork/component-library/useLogger";
import { useMountEffect } from "@react-hookz/web";
@@ -27,7 +28,6 @@ import type { CategoricalChartState } from "recharts/types/chart/types";
import { z } from "zod";
import styles from "./index.module.scss";
-import { StateType, useData } from "../../hooks/use-data";
import { Cluster, ClusterToName } from "../../services/pyth";
import type { Status } from "../../status";
import { LiveConfidence, LivePrice, LiveComponentValue } from "../LivePrices";
@@ -353,7 +353,7 @@ const ScoreBreakdown = ({
setSelectedPeriod(evaluationPeriod);
}
}}
- options={evaluationPeriods.map(({ label }) => label)}
+ options={evaluationPeriods.map(({ label }) => ({ id: label }))}
placement="bottom end"
/>
}
diff --git a/apps/insights/src/components/PriceComponentsCard/index.tsx b/apps/insights/src/components/PriceComponentsCard/index.tsx
index a549ca1dc8..5f71ce9758 100644
--- a/apps/insights/src/components/PriceComponentsCard/index.tsx
+++ b/apps/insights/src/components/PriceComponentsCard/index.tsx
@@ -3,6 +3,8 @@
import { Badge } from "@pythnetwork/component-library/Badge";
import { Button } from "@pythnetwork/component-library/Button";
import { Card } from "@pythnetwork/component-library/Card";
+import { EntityList } from "@pythnetwork/component-library/EntityList";
+import { NoResults } from "@pythnetwork/component-library/NoResults";
import { Paginator } from "@pythnetwork/component-library/Paginator";
import { SearchInput } from "@pythnetwork/component-library/SearchInput";
import { Select } from "@pythnetwork/component-library/Select";
@@ -29,12 +31,10 @@ import {
Status as StatusType,
statusNameToStatus,
} from "../../status";
-import { EntityList } from "../EntityList";
import { Explain } from "../Explain";
import { EvaluationTime } from "../Explanations";
import { FormattedNumber } from "../FormattedNumber";
import { LivePrice, LiveConfidence, LiveComponentValue } from "../LivePrices";
-import { NoResults } from "../NoResults";
import { usePriceComponentDrawer } from "../PriceComponentDrawer";
import { PriceName } from "../PriceName";
import { Score } from "../Score";
@@ -385,21 +385,21 @@ export const PriceComponentsCardContents = <
)}
-