mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2026-01-10 16:22:55 -05:00
enable experimental next/future/image (#973)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import NextLink from "next/link";
|
||||
import Link from "../Link";
|
||||
import { HeartIcon, NextjsLogo } from "../Icons";
|
||||
import { keyframes, styled } from "../../lib/styles/stitches.config";
|
||||
import * as config from "../../lib/config";
|
||||
@@ -35,18 +35,17 @@ const Row = styled("div", {
|
||||
},
|
||||
});
|
||||
|
||||
const Link = styled(NextLink, {
|
||||
const PlainLink = styled(Link, {
|
||||
color: "$mediumDark",
|
||||
textDecoration: "none",
|
||||
});
|
||||
|
||||
const NextjsLink = styled(Link, {
|
||||
const NextjsLink = styled(PlainLink, {
|
||||
"&:hover": {
|
||||
color: "$medium",
|
||||
},
|
||||
});
|
||||
|
||||
const ViewSourceLink = styled(Link, {
|
||||
const ViewSourceLink = styled(PlainLink, {
|
||||
paddingBottom: "2px",
|
||||
borderBottom: "1px solid $light",
|
||||
|
||||
@@ -89,13 +88,18 @@ const Footer = ({ ...rest }: FooterProps) => {
|
||||
<Row>
|
||||
<div>
|
||||
Content{" "}
|
||||
<Link href="/license/" prefetch={false} title="Creative Commons Attribution 4.0 International">
|
||||
<PlainLink
|
||||
href="/license/"
|
||||
prefetch={false}
|
||||
title="Creative Commons Attribution 4.0 International"
|
||||
underline={false}
|
||||
>
|
||||
licensed under CC-BY-4.0
|
||||
</Link>
|
||||
</PlainLink>
|
||||
,{" "}
|
||||
<Link href="/previously/" prefetch={false} title="Previously on...">
|
||||
<PlainLink href="/previously/" prefetch={false} title="Previously on..." underline={false}>
|
||||
2001
|
||||
</Link>{" "}
|
||||
</PlainLink>{" "}
|
||||
– {new Date(process.env.NEXT_PUBLIC_RELEASE_DATE || Date.now()).getUTCFullYear()}.
|
||||
</div>
|
||||
|
||||
@@ -105,21 +109,14 @@ const Footer = ({ ...rest }: FooterProps) => {
|
||||
<Icon as={HeartIcon} />
|
||||
</Heart>{" "}
|
||||
and{" "}
|
||||
<NextjsLink
|
||||
href="https://nextjs.org/"
|
||||
title="Powered by Next.js"
|
||||
aria-label="Next.js"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<NextjsLink href="https://nextjs.org/" title="Powered by Next.js" aria-label="Next.js" underline={false}>
|
||||
<Icon as={NextjsLogo} />
|
||||
</NextjsLink>
|
||||
.{" "}
|
||||
<ViewSourceLink
|
||||
href={`https://github.com/${config.githubRepo}`}
|
||||
title="View Source on GitHub"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
underline={false}
|
||||
>
|
||||
View source.
|
||||
</ViewSourceLink>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Link from "../Link";
|
||||
import { LinkIcon } from "../Icons";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
const AnchorLink = styled("a", {
|
||||
textDecoration: "none",
|
||||
const AnchorLink = styled(Link, {
|
||||
lineHeight: 1,
|
||||
});
|
||||
|
||||
@@ -12,14 +12,14 @@ const Icon = styled(LinkIcon, {
|
||||
height: "0.8em",
|
||||
});
|
||||
|
||||
export type HeadingAnchorProps = ComponentProps<typeof AnchorLink> & {
|
||||
export type HeadingAnchorProps = Omit<ComponentProps<typeof AnchorLink>, "href"> & {
|
||||
id: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
const HeadingAnchor = ({ id, title, ...rest }: HeadingAnchorProps) => {
|
||||
return (
|
||||
<AnchorLink href={`#${id}`} title={`Jump to "${title}"`} aria-hidden={true} {...rest}>
|
||||
<AnchorLink href={`#${id}`} title={`Jump to "${title}"`} aria-hidden={true} underline={false} {...rest}>
|
||||
<Icon />
|
||||
</AnchorLink>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import NextImage from "next/image";
|
||||
import NextImage from "next/future/image";
|
||||
import Link from "../Link";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
import type { ComponentProps } from "react";
|
||||
import type { ImageProps as NextImageProps, StaticImageData } from "next/image";
|
||||
import type { ImageProps as NextImageProps, StaticImageData } from "next/future/image";
|
||||
|
||||
// https://nextjs.org/docs/api-reference/next/image#optional-props
|
||||
const DEFAULT_QUALITY = 60;
|
||||
const DEFAULT_LAYOUT = "intrinsic";
|
||||
|
||||
const Wrapper = styled("div", {
|
||||
const Block = styled("div", {
|
||||
display: "block",
|
||||
lineHeight: 0,
|
||||
|
||||
// default to centering all images
|
||||
@@ -16,30 +13,24 @@ const Wrapper = styled("div", {
|
||||
textAlign: "center",
|
||||
});
|
||||
|
||||
const RoundedImage = styled(NextImage, {
|
||||
const StyledImage = styled(NextImage, {
|
||||
height: "auto",
|
||||
maxWidth: "100%",
|
||||
borderRadius: "$rounded",
|
||||
});
|
||||
|
||||
export type ImageProps = ComponentProps<typeof RoundedImage> & {
|
||||
export type ImageProps = ComponentProps<typeof StyledImage> & {
|
||||
href?: string; // optionally wrap image in a link
|
||||
inline?: boolean; // don't wrap everything in a `<div>` block
|
||||
};
|
||||
|
||||
const Image = ({
|
||||
src,
|
||||
width,
|
||||
height,
|
||||
quality = DEFAULT_QUALITY,
|
||||
layout = DEFAULT_LAYOUT,
|
||||
placeholder,
|
||||
href,
|
||||
...rest
|
||||
}: ImageProps) => {
|
||||
const imageProps: Partial<NextImageProps> = {
|
||||
const Image = ({ src, width, height, quality = 60, placeholder, href, inline, ...rest }: ImageProps) => {
|
||||
const imageProps: NextImageProps = {
|
||||
// strip "px" from dimensions: https://stackoverflow.com/a/4860249/1438024
|
||||
width: typeof width === "string" ? Number.parseInt(width, 10) : width,
|
||||
height: typeof height === "string" ? Number.parseInt(height, 10) : height,
|
||||
quality,
|
||||
layout,
|
||||
src,
|
||||
placeholder,
|
||||
...rest,
|
||||
};
|
||||
@@ -53,8 +44,8 @@ const Image = ({
|
||||
imageProps.placeholder = placeholder || (staticImg.blurDataURL !== undefined ? "blur" : "empty");
|
||||
} else if (typeof src === "string") {
|
||||
// regular path to a file was passed in, which makes explicit width and height required.
|
||||
// https://nextjs.org/docs/api-reference/next/image#width
|
||||
if (layout !== "fill" && (!width || !height)) {
|
||||
// https://nextjs.org/docs/api-reference/next/future/image#width
|
||||
if (!(width && height)) {
|
||||
throw new Error("'width' and 'height' are required for non-statically imported images.");
|
||||
}
|
||||
|
||||
@@ -64,18 +55,20 @@ const Image = ({
|
||||
throw new TypeError("'src' should be a string or a valid StaticImageData object.");
|
||||
}
|
||||
|
||||
const img = <RoundedImage {...(imageProps as NextImageProps)} />;
|
||||
const StyledImageWithProps = <StyledImage {...imageProps} />;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
return inline ? (
|
||||
StyledImageWithProps
|
||||
) : (
|
||||
<Block>
|
||||
{href ? (
|
||||
<Link href={href} underline={false}>
|
||||
{img}
|
||||
{StyledImageWithProps}
|
||||
</Link>
|
||||
) : (
|
||||
<>{img}</>
|
||||
StyledImageWithProps
|
||||
)}
|
||||
</Wrapper>
|
||||
</Block>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ export type LinkProps = ComponentProps<typeof StyledLink> & {
|
||||
const Link = ({ href, rel, target, prefetch = false, underline = true, openInNewTab, ...rest }: LinkProps) => {
|
||||
// This component auto-detects whether or not this link should open in the same window (the default for internal
|
||||
// links) or a new tab (the default for external links). Defaults can be overridden with `openInNewTab={true}`.
|
||||
const isExternal = typeof href === "string" && !href.startsWith("/") && !href.startsWith(baseUrl);
|
||||
const isExternal =
|
||||
typeof href === "string" && !(href.startsWith("/") || href.startsWith("#") || href.startsWith(baseUrl));
|
||||
|
||||
if (openInNewTab || isExternal) {
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import NextLink from "next/link";
|
||||
import Link from "../Link";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
|
||||
const Link = styled(NextLink, {
|
||||
const MenuLink = styled(Link, {
|
||||
display: "inline-block",
|
||||
color: "$mediumDark",
|
||||
textDecoration: "none",
|
||||
padding: "0.6em",
|
||||
|
||||
variants: {
|
||||
@@ -67,9 +66,17 @@ const MenuItem = ({ icon: ItemIcon, href, text, current, className }: MenuItemPr
|
||||
// allow both navigational links and/or other interactive react components (e.g. the theme toggle)
|
||||
if (href) {
|
||||
return (
|
||||
<Link href={href} prefetch={false} className={className} current={current} title={text} aria-label={text}>
|
||||
<MenuLink
|
||||
href={href}
|
||||
prefetch={false}
|
||||
className={className}
|
||||
current={current}
|
||||
title={text}
|
||||
underline={false}
|
||||
aria-label={text}
|
||||
>
|
||||
{linkContent}
|
||||
</Link>
|
||||
</MenuLink>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import NextLink from "next/link";
|
||||
import Link from "../Link";
|
||||
import Time from "../Time";
|
||||
import HitCounter from "../HitCounter";
|
||||
import NoteTitle from "../NoteTitle";
|
||||
@@ -21,9 +21,8 @@ const MetaItem = styled("div", {
|
||||
whiteSpace: "nowrap",
|
||||
});
|
||||
|
||||
const MetaLink = styled(NextLink, {
|
||||
const MetaLink = styled(Link, {
|
||||
color: "inherit",
|
||||
textDecoration: "none",
|
||||
});
|
||||
|
||||
const Icon = styled("svg", {
|
||||
@@ -67,6 +66,7 @@ const NoteMeta = ({ slug, date, title, htmlTitle, tags = [] }: NoteMetaProps) =>
|
||||
pathname: "/notes/[slug]/",
|
||||
query: { slug },
|
||||
}}
|
||||
underline={false}
|
||||
>
|
||||
<span>
|
||||
<Icon as={DateIcon} />
|
||||
@@ -93,9 +93,8 @@ const NoteMeta = ({ slug, date, title, htmlTitle, tags = [] }: NoteMetaProps) =>
|
||||
<MetaItem>
|
||||
<MetaLink
|
||||
href={`https://github.com/${config.githubRepo}/blob/main/notes/${slug}.mdx`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title={`Edit "${title}" on GitHub`}
|
||||
underline={false}
|
||||
>
|
||||
<span>
|
||||
<Icon as={EditIcon} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import NextLink from "next/link";
|
||||
import Link from "../Link";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
import type { ComponentProps } from "react";
|
||||
import type { NoteFrontMatter } from "../../types";
|
||||
@@ -18,9 +18,8 @@ const Title = styled("h1", {
|
||||
},
|
||||
});
|
||||
|
||||
const Link = styled(NextLink, {
|
||||
const TitleLink = styled(Link, {
|
||||
color: "$text",
|
||||
textDecoration: "none",
|
||||
});
|
||||
|
||||
export type NoteTitleProps = Pick<NoteFrontMatter, "slug" | "title" | "htmlTitle"> & ComponentProps<typeof Title>;
|
||||
@@ -28,12 +27,13 @@ export type NoteTitleProps = Pick<NoteFrontMatter, "slug" | "title" | "htmlTitle
|
||||
const NoteTitle = ({ slug, title, htmlTitle, ...rest }: NoteTitleProps) => {
|
||||
return (
|
||||
<Title {...rest}>
|
||||
<Link
|
||||
<TitleLink
|
||||
href={{
|
||||
pathname: "/notes/[slug]/",
|
||||
query: { slug },
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: htmlTitle || title }}
|
||||
underline={false}
|
||||
/>
|
||||
</Title>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import Link from "../Link";
|
||||
import { OctocatOcticon } from "../Icons";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
const Link = styled("a", {
|
||||
const GitHubLink = styled(Link, {
|
||||
margin: "0 0.4em",
|
||||
color: "$text",
|
||||
textDecoration: "none",
|
||||
|
||||
"&:hover": {
|
||||
color: "$link",
|
||||
@@ -19,15 +19,15 @@ const Octocat = styled(OctocatOcticon, {
|
||||
fill: "currentColor",
|
||||
});
|
||||
|
||||
export type OctocatLinkProps = ComponentProps<typeof Link> & {
|
||||
export type OctocatLinkProps = Omit<ComponentProps<typeof GitHubLink>, "href"> & {
|
||||
repo: string;
|
||||
};
|
||||
|
||||
const OctocatLink = ({ repo, className, ...rest }: OctocatLinkProps) => {
|
||||
return (
|
||||
<Link href={`https://github.com/${repo}`} target="_blank" rel="noopener noreferrer" {...rest}>
|
||||
<GitHubLink href={`https://github.com/${repo}`} underline={false} {...rest}>
|
||||
<Octocat className={className} />
|
||||
</Link>
|
||||
</GitHubLink>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useRouter } from "next/router";
|
||||
import NextLink from "next/link";
|
||||
import Link from "../Link";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
@@ -14,9 +14,8 @@ const Title = styled("h1", {
|
||||
},
|
||||
});
|
||||
|
||||
const Link = styled(NextLink, {
|
||||
const TitleLink = styled(Link, {
|
||||
color: "$text",
|
||||
textDecoration: "none",
|
||||
});
|
||||
|
||||
export type PageTitleProps = ComponentProps<typeof Title>;
|
||||
@@ -26,7 +25,9 @@ const PageTitle = ({ children, ...rest }: PageTitleProps) => {
|
||||
|
||||
return (
|
||||
<Title {...rest}>
|
||||
<Link href={router.pathname}>{children}</Link>
|
||||
<TitleLink href={router.pathname} underline={false}>
|
||||
{children}
|
||||
</TitleLink>
|
||||
</Title>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -41,9 +41,8 @@ const MetaItem = styled("div", {
|
||||
color: "$medium",
|
||||
});
|
||||
|
||||
const MetaLink = styled("a", {
|
||||
const MetaLink = styled(Link, {
|
||||
color: "inherit",
|
||||
textDecoration: "none",
|
||||
|
||||
"&:hover": {
|
||||
color: "$link",
|
||||
@@ -101,8 +100,7 @@ const RepositoryCard = ({
|
||||
<MetaLink
|
||||
href={`${url}/stargazers`}
|
||||
title={`${commaNumber(stars)} ${stars === 1 ? "star" : "stars"}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
underline={false}
|
||||
>
|
||||
<MetaIcon as={StarOcticon} />
|
||||
{commaNumber(stars)}
|
||||
@@ -115,8 +113,7 @@ const RepositoryCard = ({
|
||||
<MetaLink
|
||||
href={`${url}/network/members`}
|
||||
title={`${commaNumber(forks)} ${forks === 1 ? "fork" : "forks"}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
underline={false}
|
||||
>
|
||||
<MetaIcon as={ForkOcticon} />
|
||||
{commaNumber(forks)}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import NextLink from "next/link";
|
||||
import NextImage from "next/image";
|
||||
import Link from "../Link";
|
||||
import Image from "../Image";
|
||||
import { styled } from "../../lib/styles/stitches.config";
|
||||
import { authorName } from "../../lib/config";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
import selfieJpg from "../../public/static/images/selfie.jpg";
|
||||
|
||||
const Image = styled(NextImage, {
|
||||
display: "block",
|
||||
const RoundedImage = styled(Image, {
|
||||
width: "50px",
|
||||
height: "50px",
|
||||
border: "1px solid $light",
|
||||
@@ -20,17 +19,16 @@ const Image = styled(NextImage, {
|
||||
},
|
||||
});
|
||||
|
||||
const Link = styled(NextLink, {
|
||||
const SelfieLink = styled(Link, {
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
color: "$mediumDark",
|
||||
textDecoration: "none",
|
||||
|
||||
"&:hover": {
|
||||
color: "$link",
|
||||
|
||||
"@medium": {
|
||||
[`${Image}`]: {
|
||||
[`${RoundedImage}`]: {
|
||||
borderColor: "$linkUnderline",
|
||||
},
|
||||
},
|
||||
@@ -52,10 +50,18 @@ export type SelfieProps = Omit<ComponentProps<typeof Link>, "href">;
|
||||
|
||||
const Selfie = ({ ...rest }: SelfieProps) => {
|
||||
return (
|
||||
<Link href="/" rel="author" title={authorName} {...rest}>
|
||||
<Image src={selfieJpg} alt={`Photo of ${authorName}`} width={50} height={50} quality={60} layout="raw" priority />
|
||||
<SelfieLink href="/" rel="author" title={authorName} underline={false} {...rest}>
|
||||
<RoundedImage
|
||||
src={selfieJpg}
|
||||
alt={`Photo of ${authorName}`}
|
||||
width={50}
|
||||
height={50}
|
||||
quality={60}
|
||||
inline
|
||||
priority
|
||||
/>
|
||||
<Name>{authorName}</Name>
|
||||
</Link>
|
||||
</SelfieLink>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user