diff --git a/components/HitCounter/HitCounter.tsx b/components/HitCounter/HitCounter.tsx
index 8a92cd86..c5a274ea 100644
--- a/components/HitCounter/HitCounter.tsx
+++ b/components/HitCounter/HitCounter.tsx
@@ -1,7 +1,7 @@
import useSWR from "swr";
import Loading from "../Loading";
import { fetcher } from "../../lib/helpers/fetcher";
-import { siteLocale } from "../../lib/config";
+import { commafy } from "../../lib/helpers/format-number";
export type HitCounterProps = {
slug: string;
@@ -15,29 +15,22 @@ const HitCounter = ({ slug, className }: HitCounterProps) => {
revalidateOnFocus: false,
});
- try {
- // show spinning loading indicator if data isn't fetched yet
- if (!data) {
- return ;
- }
+ // show spinning loading indicator if data isn't fetched yet
+ if (!data) {
+ return ;
+ }
- // fail secretly
- if (error) {
- return null;
- }
-
- // we have data!
- return (
-
- {data.hits.toLocaleString(siteLocale)}
-
- );
- } catch (error) {
+ // fail secretly
+ if (error) {
return null;
}
+
+ // we have data!
+ return (
+
+ {commafy(data.hits)}
+
+ );
};
export default HitCounter;
diff --git a/components/Loading/Loading.tsx b/components/Loading/Loading.tsx
index 6dec73cc..2982cf6c 100644
--- a/components/Loading/Loading.tsx
+++ b/components/Loading/Loading.tsx
@@ -42,6 +42,8 @@ const Loading = ({ width, boxes = 3, timing = 0.1, css, ...rest }: LoadingProps)
key={i}
css={{
width: `${width / (boxes + 1)}px`,
+ }}
+ style={{
animationDelay: `${i * timing}s`,
}}
/>
diff --git a/components/NoteMeta/NoteMeta.tsx b/components/NoteMeta/NoteMeta.tsx
index 214184de..dee5a968 100644
--- a/components/NoteMeta/NoteMeta.tsx
+++ b/components/NoteMeta/NoteMeta.tsx
@@ -1,3 +1,4 @@
+import { ErrorBoundary } from "react-error-boundary";
import Link from "next/link";
import Time from "../Time";
import HitCounter from "../HitCounter";
@@ -108,15 +109,17 @@ const NoteMeta = ({ slug, date, title, htmlTitle, tags = [] }: NoteMetaProps) =>
{/* only count hits on production site */}
{process.env.NEXT_PUBLIC_VERCEL_ENV === "production" && (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
)}
diff --git a/components/RelativeTime/RelativeTime.tsx b/components/RelativeTime/RelativeTime.tsx
index 32209c3c..5b45ea8d 100644
--- a/components/RelativeTime/RelativeTime.tsx
+++ b/components/RelativeTime/RelativeTime.tsx
@@ -3,17 +3,20 @@ import { formatDateTZ, formatDateISO, formatTimeAgo, FlexibleDate } from "../../
export type RelativeTimeProps = {
date: FlexibleDate;
+ prefix?: string; // optional "Updated", "Published", "Created", etc.
+ staticFormat?: string; // full date (without timestamp)
className?: string;
};
-const RelativeTime = ({ date, className }: RelativeTimeProps) => {
+const RelativeTime = ({ date, prefix, staticFormat = "PP", className }: RelativeTimeProps) => {
// play nice with SSR -- only use relative time on the client, since it'll quickly become outdated on the server and
// cause a react hydration mismatch error.
const hasMounted = useHasMounted();
return (
);
};
diff --git a/components/RepositoryCard/RepositoryCard.tsx b/components/RepositoryCard/RepositoryCard.tsx
index 8fc2fed3..dcbca333 100644
--- a/components/RepositoryCard/RepositoryCard.tsx
+++ b/components/RepositoryCard/RepositoryCard.tsx
@@ -1,8 +1,8 @@
import Link from "../Link";
import RelativeTime from "../RelativeTime";
import { StarOcticon, ForkOcticon } from "../Icons";
+import { commafy } from "../../lib/helpers/format-number";
import { styled } from "../../lib/styles/stitches.config";
-import { siteLocale } from "../../lib/config";
import type { RepositoryType } from "../../types";
const Wrapper = styled("div", {
@@ -100,12 +100,12 @@ const RepositoryCard = ({
- {stars.toLocaleString(siteLocale)}
+ {commafy(stars)}
)}
@@ -114,19 +114,19 @@ const RepositoryCard = ({
- {forks.toLocaleString(siteLocale)}
+ {commafy(forks)}
)}
{/* only use relative "time ago" on client side, since it'll be outdated via SSG and cause hydration errors */}
-
+
diff --git a/components/ThemeScript/ThemeScript.tsx b/components/ThemeScript/ThemeScript.tsx
index b86de280..0c666a51 100644
--- a/components/ThemeScript/ThemeScript.tsx
+++ b/components/ThemeScript/ThemeScript.tsx
@@ -1,32 +1,34 @@
-import { memo } from "react";
+import { useMemo } from "react";
import { minify } from "uglify-js";
import { clientScript } from "./script";
import { darkModeQuery, themeStorageKey, themeClassNames } from "../../lib/config/themes";
const ThemeScript = () => {
- // since the function above will end up being injected as a plain dumb string, we need to set the dynamic values here:
- const functionString = String(clientScript)
- .replace('"__MEDIA_QUERY__"', `"${darkModeQuery}"`)
- .replace('"__STORAGE_KEY__"', `"${themeStorageKey}"`)
- .replace('"__CLASS_NAMES__"', JSON.stringify(themeClassNames))
- .replace(
- '"__LIST_OF_CLASSES__"',
- Object.values(themeClassNames)
- .map((t: string) => `"${t}"`)
- .join(",")
- );
+ const minified = useMemo(() => {
+ // since the client function will end up being injected as a plain dumb string, we need to set dynamic values here:
+ const functionString = String(clientScript)
+ .replace('"__MEDIA_QUERY__"', `"${darkModeQuery}"`)
+ .replace('"__STORAGE_KEY__"', `"${themeStorageKey}"`)
+ .replace('"__CLASS_NAMES__"', JSON.stringify(themeClassNames))
+ .replace(
+ '"__LIST_OF_CLASSES__"',
+ Object.values(themeClassNames)
+ .map((t) => `"${t}"`)
+ .join(",")
+ );
- // minify the final code, a bit hacky but this is ONLY done at build-time, so uglify-js is never bundled or sent to
- // the browser to execute:
- const minified = minify(`(${functionString})()`, {
- toplevel: true,
- compress: {
- negate_iife: false,
- },
- parse: {
- bare_returns: true,
- },
- }).code;
+ // minify the final code, a bit hacky but this is ONLY done at build-time, so uglify-js is never bundled or sent to
+ // the browser to execute:
+ return minify(`(${functionString})()`, {
+ toplevel: true,
+ compress: {
+ negate_iife: false,
+ },
+ parse: {
+ bare_returns: true,
+ },
+ }).code;
+ }, []);
// the script tag injected manually into `
` in _document.tsx.
// even though it's the proper method, using next/script with `strategy="beforeInteractive"` still causes flash of
@@ -36,10 +38,10 @@ const ThemeScript = () => {
key="restore-theme"
dangerouslySetInnerHTML={{
// make it an IIFE:
- __html: `(function(){${minified}})();`,
+ __html: `(function(){${minified}})()`,
}}
/>
);
};
-export default memo(ThemeScript);
+export default ThemeScript;
diff --git a/components/ThemeScript/script.js b/components/ThemeScript/script.js
index c906d471..fd7e10f1 100644
--- a/components/ThemeScript/script.js
+++ b/components/ThemeScript/script.js
@@ -1,7 +1,7 @@
-/* eslint-disable no-var */
+/* eslint-disable no-empty, no-var, prefer-destructuring */
// this function is converted to a string verbatim, substitutions are made to insert dynamic values, minified, and then
-// finally exported as an inline `