Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ patches/
# build graph config.
apps/api-reference
apps/staking
apps/insights
governance/pyth_staking_sdk
packages/component-library
packages/fonts
packages/*
1 change: 1 addition & 0 deletions apps/insights/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env*.local
7 changes: 7 additions & 0 deletions apps/insights/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.next/
coverage/
node_modules/
*.tsbuildinfo
.env*.local
.env
.DS_Store
9 changes: 9 additions & 0 deletions apps/insights/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { fileURLToPath } from "node:url";

import { nextjs, tailwind, storybook } from "@cprussin/eslint-config";

const tailwindConfig = fileURLToPath(
import.meta.resolve(`./tailwind.config.ts`),
);

export default [...nextjs, ...tailwind(tailwindConfig), ...storybook];
1 change: 1 addition & 0 deletions apps/insights/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { nextjs as default } from "@cprussin/jest-config";
5 changes: 5 additions & 0 deletions apps/insights/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
56 changes: 56 additions & 0 deletions apps/insights/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const config = {
reactStrictMode: true,

pageExtensions: ["ts", "tsx", "mdx"],

logging: {
fetches: {
fullUrl: true,
},
},

webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
use: ["@svgr/webpack"],
});

config.resolve.extensionAlias = {
".js": [".js", ".ts", ".tsx"],
};

return config;
},

transpilePackages: ["@pythnetwork/*"],

headers: async () => [
{
source: "/:path*",
headers: [
{
key: "X-XSS-Protection",
value: "1; mode=block",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{
key: "Strict-Transport-Security",
value: "max-age=2592000",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Permissions-Policy",
value:
"vibrate=(), geolocation=(), midi=(), notifications=(), push=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), speaker=(), vibrate=(), fullscreen=self",
},
],
},
],
};
export default config;
48 changes: 48 additions & 0 deletions apps/insights/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@pythnetwork/insights",
"version": "0.0.0",
"private": true,
"type": "module",
"engines": {
"node": "20"
},
"scripts": {
"build": "next build",
"fix:format": "prettier --write .",
"fix:lint": "eslint --fix .",
"start:dev": "next dev --port 3003",
"start:prod": "next start --port 3003",
"test:format": "prettier --check .",
"test:lint": "jest --selectProjects lint",
"test:types": "tsc"
},
"dependencies": {
"@pythnetwork/app-logger": "workspace:*",
"@pythnetwork/component-library": "workspace:*",
"@pythnetwork/fonts": "workspace:*",
"@pythnetwork/next-root": "workspace:*",
"clsx": "catalog:",
"next": "catalog:",
"react": "catalog:",
"react-dom": "catalog:"
},
"devDependencies": {
"@cprussin/eslint-config": "catalog:",
"@cprussin/jest-config": "catalog:",
"@cprussin/prettier-config": "catalog:",
"@cprussin/tsconfig": "catalog:",
"@svgr/webpack": "catalog:",
"@types/jest": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"autoprefixer": "catalog:",
"eslint": "catalog:",
"jest": "catalog:",
"postcss": "catalog:",
"prettier": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:",
"vercel": "catalog:"
}
}
6 changes: 6 additions & 0 deletions apps/insights/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
autoprefixer: {},
tailwindcss: {},
},
};
9 changes: 9 additions & 0 deletions apps/insights/prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { fileURLToPath } from "node:url";

import { base, tailwind, mergeConfigs } from "@cprussin/prettier-config";

const tailwindConfig = fileURLToPath(
import.meta.resolve(`./tailwind.config.ts`),
);

export default mergeConfigs([base, tailwind(tailwindConfig)]);
Binary file added apps/insights/public/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/insights/public/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/insights/public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/insights/public/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/insights/public/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/insights/public/favicon-light.ico
Binary file not shown.
Binary file added apps/insights/public/favicon.ico
Binary file not shown.
3 changes: 3 additions & 0 deletions apps/insights/src/app/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use client";

export { Error as default } from "../components/Error";
14 changes: 14 additions & 0 deletions apps/insights/src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use client";

import type { ComponentProps } from "react";

import { Error } from "../components/Error";

const GlobalError = (props: ComponentProps<typeof Error>) => (
<html lang="en" dir="ltr">
<body>
<Error {...props} />
</body>
</html>
);
export default GlobalError;
4 changes: 4 additions & 0 deletions apps/insights/src/app/layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import "../tailwind.css";

export { Root as default } from "../components/Root";
export { metadata, viewport } from "../metadata";
25 changes: 25 additions & 0 deletions apps/insights/src/app/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { MetadataRoute } from "next";

import { metadata, viewport } from "../metadata";

const manifest = (): MetadataRoute.Manifest => ({
name: metadata.applicationName,
short_name: metadata.applicationName,
description: metadata.description,
theme_color: viewport.themeColor,
background_color: viewport.themeColor,
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
display: "standalone",
});
export default manifest;
1 change: 1 addition & 0 deletions apps/insights/src/app/not-found.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { NotFound as default } from "../components/NotFound";
1 change: 1 addition & 0 deletions apps/insights/src/app/page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Home as default } from "../components/Home";
11 changes: 11 additions & 0 deletions apps/insights/src/app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { MetadataRoute } from "next";

import { IS_PRODUCTION_SERVER } from "../config/server";

const robots = (): MetadataRoute.Robots => ({
rules: {
userAgent: "*",
...(IS_PRODUCTION_SERVER ? { allow: "/" } : { disallow: "/" }),
},
});
export default robots;
27 changes: 27 additions & 0 deletions apps/insights/src/components/Error/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useLogger } from "@pythnetwork/app-logger";
import { Button } from "@pythnetwork/component-library/Button";
import { useEffect } from "react";

type Props = {
error: Error & { digest?: string };
reset?: () => void;
};

export const Error = ({ error, reset }: Props) => {
const logger = useLogger();

useEffect(() => {
logger.error(error);
}, [error, logger]);

return (
<main>
<h1>Uh oh!</h1>
<h2>Something went wrong</h2>
<p>
Error Details: <strong>{error.digest ?? error.message}</strong>
</p>
{reset && <Button onPress={reset}>Reset</Button>}
</main>
);
};
5 changes: 5 additions & 0 deletions apps/insights/src/components/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const Home = () => (
<main>
<h1>Hello world!</h1>
</main>
);
9 changes: 9 additions & 0 deletions apps/insights/src/components/NotFound/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ButtonLink } from "@pythnetwork/component-library/Button";

export const NotFound = () => (
<main>
<h1>Not Found</h1>
<p>{"The page you're looking for isn't here"}</p>
<ButtonLink href="/">Go Home</ButtonLink>
</main>
);
31 changes: 31 additions & 0 deletions apps/insights/src/components/Root/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { sans } from "@pythnetwork/fonts";
import { Root as BaseRoot } from "@pythnetwork/next-root";
import clsx from "clsx";
import type { ReactNode } from "react";

import {
IS_PRODUCTION_SERVER,
GOOGLE_ANALYTICS_ID,
AMPLITUDE_API_KEY,
} from "../../config/server";

type Props = {
children: ReactNode;
};

export const Root = ({ children }: Props) => (
<BaseRoot
amplitudeApiKey={AMPLITUDE_API_KEY}
googleAnalyticsId={GOOGLE_ANALYTICS_ID}
enableAccessibilityReporting={!IS_PRODUCTION_SERVER}
>
<body
className={clsx(
"bg-white font-sans text-steel-900 antialiased dark:bg-steel-900 dark:text-steel-50",
sans.variable,
)}
>
{children}
</body>
</BaseRoot>
);
13 changes: 13 additions & 0 deletions apps/insights/src/config/isomorphic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-disable n/no-process-env */

/**
* Indicates this is a production-optimized build. Note this does NOT
* necessarily indicate that we're running on a cloud machine or the live build
* -- use `RUNNING_IN_CLOUD` or `IS_PRODUCTION_SERVER` out of `config/server.ts`
* for that (if you need that on the client you'll need to write a client
* component that receives that value as a prop).
*
* Basically this indicates if we're minified, excluding source maps, running
* with the optimized React build, etc.
*/
export const IS_PRODUCTION_BUILD = process.env.NODE_ENV === "production";
45 changes: 45 additions & 0 deletions apps/insights/src/config/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Disable the following rule because this file is the intended place to declare
// and load all env variables.
/* eslint-disable n/no-process-env */

// Disable the following rule because variables in this file are only loaded at
// runtime and do not influence the build outputs, thus they need not be
// declared to turbo for it to be able to cache build outputs correctly.
/* eslint-disable turbo/no-undeclared-env-vars */

import "server-only";

/**
* Throw if the env var `key` is not set (at either runtime or build time).
*/
const demand = (key: string): string => {
const value = process.env[key];
if (value === undefined || value === "") {
throw new MissingEnvironmentError(key);
} else {
return value;
}
};

/**
* Indicates that this server is the live customer-facing production server.
*/
export const IS_PRODUCTION_SERVER = process.env.VERCEL_ENV === "production";

/**
* Throw if the env var `key` is not set in the live customer-facing production
* server, but allow it to be unset in any other environment.
*/
const demandInProduction = IS_PRODUCTION_SERVER
? demand
: (key: string) => process.env[key];

export const GOOGLE_ANALYTICS_ID = demandInProduction("GOOGLE_ANALYTICS_ID");
export const AMPLITUDE_API_KEY = demandInProduction("AMPLITUDE_API_KEY");

class MissingEnvironmentError extends Error {
constructor(name: string) {
super(`Missing environment variable: ${name}!`);
this.name = "MissingEnvironmentError";
}
}
Loading
Loading