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 `