(
}
*:focus-visible {
outline-color: ${colors.primaryDark};
- outline-style: solid;
- outline-width: 2px;
- border-radius: 3px;
+ }
+ .TooltipContent {
+ background-color: ${darkColors.black};
+ border: 1px solid ${context.isDark ? colors.gray7 : colors.gray6};
+ }
+ .TooltipContent svg {
+ stroke: ${context.isDark ? colors.gray7 : colors.gray6};
}`}
diff --git a/pages/_document.tsx b/pages/_document.tsx
index 5edef4eb0..c92ae1ba3 100644
--- a/pages/_document.tsx
+++ b/pages/_document.tsx
@@ -1,59 +1,57 @@
-import Document, { DocumentContext, Html, Head, Main, NextScript } from 'next/document';
+import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document';
import GoogleAnalytics from '~/components/GoogleAnalytics';
import { StructuredData } from '~/components/StructuredData';
-class DirectoryWebsite extends Document {
- static async getInitialProps(ctx: DocumentContext) {
- const initialProps = await Document.getInitialProps(ctx);
- return { ...initialProps };
- }
-
- render = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
- );
-}
+ 'query-input': 'required name=search_term_string',
+ },
+ }}
+ />
+
+
+
+
+
+
+);
+
+DirectoryWebsite.getInitialProps = async (ctx: DocumentContext) => {
+ const initialProps = await Document.getInitialProps(ctx);
+ return { ...initialProps };
+};
export default DirectoryWebsite;
diff --git a/pages/_error.jsx b/pages/_error.jsx
deleted file mode 100644
index 6a216628e..000000000
--- a/pages/_error.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-// NOTE(brentvatne):
-// This is the default Sentry error page provided by https://github.com/vercel/next.js/tree/canary/examples/with-sentry/
-
-import * as Sentry from '@sentry/react';
-import Error from 'next/error';
-
-import ErrorState from '~/components/ErrorState';
-
-function MyError({ statusCode, hasGetInitialPropsRun, err }) {
- if (!hasGetInitialPropsRun && err) {
- // getInitialProps is not called in case of
- // https://github.com/zeit/next.js/issues/8592. As a workaround, we pass
- // err via _app.js so it can be captured
- Sentry.captureException(err);
- }
-
- return ;
-}
-
-MyError.getInitialProps = async ({ res, err }) => {
- const errorInitialProps = await Error.getInitialProps({ res, err });
-
- // Workaround for https://github.com/zeit/next.js/issues/8592, mark when
- // getInitialProps has run
- errorInitialProps.hasGetInitialPropsRun = true;
-
- if (res) {
- // Running on the server, the response object is available.
- //
- // Next.js will pass an err on the server if a page's `getInitialProps`
- // threw or returned a Promise that rejected
- if (err) {
- Sentry.captureException(err);
- return errorInitialProps;
- }
- } else {
- // Running on the client (browser).
- //
- // Next.js will provide an err if:
- //
- // - a page's `getInitialProps` threw or returned a Promise that rejected
- // - an exception was thrown somewhere in the React lifecycle (render,
- // componentDidMount, etc) that was caught by Next.js's React Error
- // Boundary. Read more about what types of exceptions are caught by Error
- // Boundaries: https://reactjs.org/docs/error-boundaries.html
- if (err) {
- Sentry.captureException(err);
- return errorInitialProps;
- }
- }
-
- // If this point is reached, getInitialProps was called without any
- // information about what the error might be. This is unexpected and may
- // indicate a bug introduced in Next.js, so record it in Sentry
- // Sentry.captureException(new Error(`_error.js getInitialProps missing data at path: ${asPath}`));
-
- return errorInitialProps;
-};
-
-export default MyError;
diff --git a/pages/_error.tsx b/pages/_error.tsx
new file mode 100644
index 000000000..7eb7136db
--- /dev/null
+++ b/pages/_error.tsx
@@ -0,0 +1,35 @@
+// This code is based on the default Sentry error page provided by https://github.com/vercel/next.js/blob/canary/examples/with-sentry/pages/_error.tsx
+// It has been altered to use `@sentry/react` and to handle https://github.com/vercel/next.js/issues/8592
+
+import * as Sentry from '@sentry/react';
+import { type NextPageContext } from 'next';
+import Error, { type ErrorProps } from 'next/error';
+
+import ErrorState from '~/components/ErrorState';
+
+type ExtendedErrorProps = ErrorProps & {
+ hasGetInitialPropsRun?: boolean;
+};
+
+function MyError({ statusCode, hasGetInitialPropsRun, err }) {
+ if (!hasGetInitialPropsRun && err) {
+ Sentry.captureException(err);
+ }
+
+ return ;
+}
+
+MyError.getInitialProps = async (nextPageContext: NextPageContext) => {
+ const errorInitialProps: ExtendedErrorProps = await Error.getInitialProps(nextPageContext);
+
+ errorInitialProps.hasGetInitialPropsRun = true;
+
+ if (nextPageContext.err) {
+ Sentry.captureException(nextPageContext.err);
+ return errorInitialProps;
+ }
+
+ return errorInitialProps;
+};
+
+export default MyError;
diff --git a/scripts/fetch-npm-registry-data.ts b/scripts/fetch-npm-registry-data.ts
index 7f0d0a9d9..3f59ba689 100644
--- a/scripts/fetch-npm-registry-data.ts
+++ b/scripts/fetch-npm-registry-data.ts
@@ -25,9 +25,9 @@ export async function fetchNpmRegistryData(pkgData: LibraryType, attemptsCount =
return { ...pkgData, npm: pkgData.npm };
}
- const latestVersion = registryData['dist-tags'].latest;
+ const latestRelease = registryData['dist-tags'].latest;
- if (!latestVersion) {
+ if (!latestRelease) {
console.warn(
`[NPM REGISTRY API] ${npmPkg} doesn't have the "latest" tag, skipping bundle size!`
);
@@ -38,7 +38,9 @@ export async function fetchNpmRegistryData(pkgData: LibraryType, attemptsCount =
...pkgData,
npm: {
...pkgData.npm,
- size: registryData.versions[latestVersion].dist.unpackedSize,
+ size: registryData.versions[latestRelease].dist.unpackedSize,
+ latestRelease,
+ latestReleaseDate: registryData.time[latestRelease],
},
};
} catch (error) {
diff --git a/styles/styles.css b/styles/styles.css
index 7ff348b5c..93d11f185 100644
--- a/styles/styles.css
+++ b/styles/styles.css
@@ -22,6 +22,12 @@
font-style: normal;
}
+*:focus-visible {
+ outline-style: solid;
+ outline-width: 2px;
+ border-radius: 3px;
+}
+
html, body {
min-height: 100%;
font-family: "Optimistic Display", system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
@@ -35,6 +41,10 @@ select {
outline-offset: 2px;
}
+input:focus-visible {
+ border-radius: 6px;
+}
+
#__next, #__next > div {
min-height: 100vh;
}
@@ -42,13 +52,12 @@ select {
/* TOOLTIP */
.TooltipContent {
- border-radius: 4px;
+ border-radius: 6px;
padding: 6px 12px;
font-size: 13px;
line-height: 1.5;
color: #fff;
- background-color: #000;
- box-shadow: hsl(206 22% 7% / 40%) 0 10px 38px -10px, hsl(206 22% 7% / 25%) 0 10px 20px -15px;
+ box-shadow: hsl(206 22% 7% / 40%) 0 10px 32px -8px, hsl(206 22% 7% / 25%) 0 10px 18px -12px;
user-select: none;
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
diff --git a/types/index.ts b/types/index.ts
index a4f8f5928..bb10a1ca1 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -90,6 +90,8 @@ export type LibraryType = LibraryDataEntryType & {
downloads?: number;
weekDownloads?: number;
size?: number;
+ latestRelease?: string;
+ latestReleaseDate?: string;
};
npmPkg: string;
score: number;
diff --git a/util/getApiUrl.ts b/util/getApiUrl.ts
index a83355bc0..9996ff704 100644
--- a/util/getApiUrl.ts
+++ b/util/getApiUrl.ts
@@ -1,7 +1,6 @@
import { NextPageContext } from 'next';
-export default function getApiUrl(path: string, ctx: NextPageContext) {
- const { req } = ctx;
+export default function getApiUrl(path: string, { req }: NextPageContext) {
if (!req && typeof window !== 'undefined') {
return `/api${path}`;
}
@@ -10,5 +9,6 @@ export default function getApiUrl(path: string, ctx: NextPageContext) {
const proto = req
? (req.headers['x-forwarded-proto'] ?? 'http')
: window.location.protocol.slice(0, -1);
+
return `${proto}://${host}/api${path}`;
}
diff --git a/util/newArchStatus.ts b/util/newArchStatus.ts
index 7ca1d3792..96b86fbcf 100644
--- a/util/newArchStatus.ts
+++ b/util/newArchStatus.ts
@@ -9,7 +9,7 @@ export enum NewArchSupportStatus {
export function getNewArchSupportStatus({ newArchitecture, github, expoGo }: LibraryType) {
// Assume untested unless indicated otherwise through one of the following tests
- let flag: boolean | string | undefined = undefined;
+ let flag: LibraryType['newArchitecture'] = undefined;
if (typeof newArchitecture !== 'undefined') {
flag = newArchitecture;
diff --git a/util/strings.ts b/util/strings.ts
index 873a4b570..8aa5d6e3b 100644
--- a/util/strings.ts
+++ b/util/strings.ts
@@ -1,5 +1,17 @@
-export function pluralize(text: string, count: number) {
- return count > 1 || count === 0 ? `${text}s` : text;
+export function pluralize(word: string, count: number) {
+ if (count === 1) {
+ return word;
+ }
+
+ if (/[^aeiou]y$/i.test(word)) {
+ return word.replace(/y$/i, 'ies');
+ }
+
+ if (/(s|sh|ch|x|z)$/i.test(word)) {
+ return `${word}es`;
+ }
+
+ return `${word}s`;
}
export function isEmptyOrNull(text?: string) {