1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-04-26 09:05:22 -04:00

switch from date-fns (and date-fns-tz) to dayjs

This commit is contained in:
Jake Jarvis 2022-04-22 14:37:35 -04:00
parent 8a97b706be
commit fbb2221d08
Signed by: jake
GPG Key ID: 2B0C9CF251E69A39
10 changed files with 78 additions and 58 deletions

View File

@ -1,26 +1,26 @@
// Icons from various packs, imported directly from the package's SVG files instead of their exports so they're all
// processed consistently via svgr/webpack into React components.
// NOTE: each node_modules/ directory *must* be listed in svgr's webpack config in next.config.js.
// NOTE: each package's path inside ./node_modules *must* be listed in svgr's webpack config in next.config.js.
// feather icons: https://feathericons.com/
export { default as ContactIcon } from "../../node_modules/feather-icons/dist/icons/mail.svg";
export { default as DateIcon } from "../../node_modules/feather-icons/dist/icons/calendar.svg";
export { default as EditIcon } from "../../node_modules/feather-icons/dist/icons/edit.svg";
export { default as HomeIcon } from "../../node_modules/feather-icons/dist/icons/home.svg";
export { default as NotesIcon } from "../../node_modules/feather-icons/dist/icons/edit-3.svg";
export { default as ProjectsIcon } from "../../node_modules/feather-icons/dist/icons/code.svg";
export { default as TagIcon } from "../../node_modules/feather-icons/dist/icons/tag.svg";
export { default as ViewsIcon } from "../../node_modules/feather-icons/dist/icons/eye.svg";
export { default as ContactIcon } from "feather-icons/dist/icons/mail.svg";
export { default as DateIcon } from "feather-icons/dist/icons/calendar.svg";
export { default as EditIcon } from "feather-icons/dist/icons/edit.svg";
export { default as HomeIcon } from "feather-icons/dist/icons/home.svg";
export { default as NotesIcon } from "feather-icons/dist/icons/edit-3.svg";
export { default as ProjectsIcon } from "feather-icons/dist/icons/code.svg";
export { default as TagIcon } from "feather-icons/dist/icons/tag.svg";
export { default as ViewsIcon } from "feather-icons/dist/icons/eye.svg";
// octicons: https://primer.style/octicons/
export { default as CheckOcticon } from "../../node_modules/@primer/octicons/build/svg/check-16.svg";
export { default as ClipboardOcticon } from "../../node_modules/@primer/octicons/build/svg/paste-16.svg";
export { default as ForkOcticon } from "../../node_modules/@primer/octicons/build/svg/repo-forked-16.svg";
export { default as HeartIcon } from "../../node_modules/@primer/octicons/build/svg/heart-fill-16.svg";
export { default as MarkdownIcon } from "../../node_modules/@primer/octicons/build/svg/markdown-16.svg";
export { default as OctocatOcticon } from "../../node_modules/@primer/octicons/build/svg/mark-github-16.svg";
export { default as StarOcticon } from "../../node_modules/@primer/octicons/build/svg/star-16.svg";
export { default as XOcticon } from "../../node_modules/@primer/octicons/build/svg/x-16.svg";
export { default as CheckOcticon } from "@primer/octicons/build/svg/check-16.svg";
export { default as ClipboardOcticon } from "@primer/octicons/build/svg/paste-16.svg";
export { default as ForkOcticon } from "@primer/octicons/build/svg/repo-forked-16.svg";
export { default as HeartIcon } from "@primer/octicons/build/svg/heart-fill-16.svg";
export { default as MarkdownIcon } from "@primer/octicons/build/svg/markdown-16.svg";
export { default as OctocatOcticon } from "@primer/octicons/build/svg/mark-github-16.svg";
export { default as StarOcticon } from "@primer/octicons/build/svg/star-16.svg";
export { default as XOcticon } from "@primer/octicons/build/svg/x-16.svg";
// simple icons: https://simpleicons.org/
export { default as NextjsLogo } from "../../node_modules/simple-icons/icons/nextdotjs.svg";
export { default as NextjsLogo } from "simple-icons/icons/nextdotjs.svg";

View File

@ -73,7 +73,7 @@ const NoteMeta = ({ slug, date, title, htmlTitle, tags = [] }: NoteMetaProps) =>
<span>
<Icon as={DateIcon} />
</span>
<Time date={date} format="MMMM d, yyyy" />
<Time date={date} format="MMMM D, YYYY" />
</MetaLink>
</Link>
</MetaItem>

View File

@ -67,7 +67,7 @@ const NotesList = ({ notesByYear }: NotesListProps) => {
<List>
{notes.map(({ slug, date, htmlTitle }) => (
<Post key={slug}>
<PostDate date={date} format="MMM d" />
<PostDate date={date} format="MMM D" />
<span>
<Link
href={{

View File

@ -1,22 +1,22 @@
import { useHasMounted } from "../../hooks/use-has-mounted";
import { formatDateTZ, formatDateISO, formatTimeAgo, FlexibleDate } from "../../lib/helpers/format-date";
import { formatDate, formatDateISO, formatTimeAgo } from "../../lib/helpers/format-date";
export type RelativeTimeProps = {
date: FlexibleDate;
prefix?: string; // optional "Updated", "Published", "Created", etc.
staticFormat?: string; // full date (without timestamp)
date: string | number | Date;
verb?: string; // optional "Updated", "Published", "Created", etc.
staticFormat?: string; // format for the placeholder/fallback before client-side renders the relative time
className?: string;
};
const RelativeTime = ({ date, prefix, staticFormat = "PP", className }: RelativeTimeProps) => {
const RelativeTime = ({ date, verb, staticFormat, 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 (
<time dateTime={formatDateISO(date)} title={formatDateTZ(date)} className={className}>
{prefix && `${prefix} `}
{hasMounted ? formatTimeAgo(date) : `on ${formatDateTZ(date, staticFormat)}`}
<time dateTime={formatDateISO(date)} title={formatDate(date)} className={className}>
{verb && `${verb} `}
{hasMounted ? formatTimeAgo(date, true) : `on ${formatDate(date, staticFormat)}`}
</time>
);
};

View File

@ -126,7 +126,7 @@ const RepositoryCard = ({
{/* only use relative "time ago" on client side, since it'll be outdated via SSG and cause hydration errors */}
<MetaItem>
<RelativeTime date={updatedAt} prefix="Updated" />
<RelativeTime date={updatedAt} verb="Updated" />
</MetaItem>
</Meta>
</Wrapper>

View File

@ -1,14 +1,14 @@
import { formatDateTZ, formatDateISO, FlexibleDate } from "../../lib/helpers/format-date";
import { formatDate, formatDateISO } from "../../lib/helpers/format-date";
export type TimeProps = {
date: FlexibleDate;
date: string | number | Date;
format?: string;
className?: string;
};
const Time = ({ date, format = "MMM d", className }: TimeProps) => (
<time dateTime={formatDateISO(date)} title={formatDateTZ(date)} className={className}>
{formatDateTZ(date, format)}
const Time = ({ date, format = "MMM D", className }: TimeProps) => (
<time dateTime={formatDateISO(date)} title={formatDate(date)} className={className}>
{formatDate(date, format)}
</time>
);

View File

@ -1,22 +1,42 @@
import { formatDistanceToNowStrict } from "date-fns";
import { formatInTimeZone } from "date-fns-tz";
import enUS from "date-fns/locale/en-US";
import dayjs from "dayjs";
import dayjsUtc from "dayjs/plugin/utc";
import dayjsTimezone from "dayjs/plugin/timezone";
import dayjsRelativeTime from "dayjs/plugin/relativeTime";
import dayjsLocalizedFormat from "dayjs/plugin/localizedFormat";
import dayjsAdvancedFormat from "dayjs/plugin/advancedFormat";
import "dayjs/locale/en";
import { timeZone } from "../config";
export type FlexibleDate = string | number | Date;
const IsomorphicDayJs = (date?: dayjs.ConfigType): dayjs.Dayjs => {
// plugins
dayjs.extend(dayjsUtc);
dayjs.extend(dayjsTimezone);
dayjs.extend(dayjsRelativeTime);
dayjs.extend(dayjsLocalizedFormat);
dayjs.extend(dayjsAdvancedFormat);
// defaults
dayjs.locale("en");
dayjs.tz.setDefault(timeZone);
return dayjs(date);
};
// normalize timezone across the site, both server and client side, to prevent hydration errors.
// format defaults to "Apr 4, 2022, 3:04 PM EDT", see https://date-fns.org/v2.28.0/docs/format
export const formatDateTZ = (date: FlexibleDate, formatStr = "PPp zzz", options = {}) => {
return formatInTimeZone(new Date(date), timeZone, formatStr, { locale: enUS, ...options });
// format defaults to "Apr 4, 2022, 3:04 PM EDT", see https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens
export const formatDate = (date?: dayjs.ConfigType, formatStr = "MMM D, YYYY, h:mm A z") => {
return IsomorphicDayJs(date).tz(timeZone).format(formatStr);
};
// returns a timezone-less, machine-readable string.
export const formatDateISO = (date: FlexibleDate) => {
return new Date(date).toISOString();
export const formatDateISO = (date?: dayjs.ConfigType) => {
return IsomorphicDayJs(date).toISOString();
};
// returns "5 minutes ago", "1 year ago", etc.
export const formatTimeAgo = (date: FlexibleDate, options = {}) => {
return formatDistanceToNowStrict(new Date(date), { addSuffix: true, locale: enUS, ...options });
// returns "5 minutes ago", "1 year ago", "in 9 months", etc.
// set `suffix = false` to exclude the "in" or "ago"
export const formatTimeAgo = (date: dayjs.ConfigType, suffix = true) => {
return IsomorphicDayJs().isBefore(date)
? IsomorphicDayJs(date).toNow(!suffix)
: IsomorphicDayJs(date).fromNow(!suffix);
};

View File

@ -2,4 +2,10 @@ import { siteLocale } from "../config";
// adds thousands separator
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
export const commafy = Intl.NumberFormat(siteLocale, { useGrouping: true }).format;
export const commafy = (number: number) => {
if (typeof Intl !== "undefined" && typeof Intl.NumberFormat !== "undefined") {
return new Intl.NumberFormat(siteLocale, { useGrouping: true }).format(number);
} else {
return number;
}
};

View File

@ -31,8 +31,7 @@
"@sentry/tracing": "^6.19.6",
"@stitches/react": "^1.2.7",
"copy-to-clipboard": "^3.3.1",
"date-fns": "^2.28.0",
"date-fns-tz": "^1.3.3",
"dayjs": "^1.11.1",
"fathom-client": "^3.4.1",
"faunadb": "^4.5.4",
"feather-icons": "^4.29.0",

View File

@ -2419,15 +2419,10 @@ data-uri-to-buffer@^4.0.0:
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
date-fns-tz@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.3.tgz#7884a4b3ed6cd95bfd81831d608e5ef8be500c86"
integrity sha512-Gks46gwbSauBQnV3Oofluj1wTm8J0tM7sbSJ9P+cJq/ZnTCpMohTKmmO5Tn+jQ7dyn0+b8G7cY4O2DZ5P/LXcA==
date-fns@^2.28.0:
version "2.28.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2"
integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==
dayjs@^1.11.1:
version "1.11.1"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.1.tgz#90b33a3dda3417258d48ad2771b415def6545eb0"
integrity sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==
debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3:
version "4.3.4"