improve SEO

This commit is contained in:
Johannes Kirschbauer 2024-01-22 14:36:57 +01:00
parent 53912303f3
commit f938e1f95a
No known key found for this signature in database
12 changed files with 84 additions and 22 deletions

View File

@ -3,7 +3,7 @@ import { ShareButton } from "@/components/ShareButton";
import { BackButton } from "@/components/BackButton"; import { BackButton } from "@/components/BackButton";
import { Doc, data, manualLinks } from "@/models/data"; import { Doc, data, manualLinks } from "@/models/data";
import { getPrimopDescription } from "@/models/primop"; import { getPrimopDescription } from "@/models/primop";
import { extractHeadings, mdxRenderOptions } from "@/utils"; import { extractExcerpt, extractHeadings, mdxRenderOptions } from "@/utils";
import { Box, Divider, Typography, Link, Chip } from "@mui/material"; import { Box, Divider, Typography, Link, Chip } from "@mui/material";
import { MDXRemote } from "next-mdx-remote/rsc"; import { MDXRemote } from "next-mdx-remote/rsc";
import { findType, interpretType } from "@/models/nix"; import { findType, interpretType } from "@/models/nix";
@ -50,10 +50,12 @@ const Toc = async (props: TocProps) => {
whiteSpace: "nowrap", whiteSpace: "nowrap",
}} }}
> >
<Typography variant="subtitle1">On this page</Typography> <Typography variant="subtitle1" component={"div"}>
On this page
</Typography>
<Box sx={{ display: "flex", flexDirection: "column" }}> <Box sx={{ display: "flex", flexDirection: "column" }}>
{title && ( {title && (
<Link href={`#${title}`}> <Link rel="canonical" href={`#${title}`}>
<Typography <Typography
variant="body2" variant="body2"
sx={{ sx={{
@ -68,7 +70,7 @@ const Toc = async (props: TocProps) => {
</Link> </Link>
)} )}
{headings.map((h, idx) => ( {headings.map((h, idx) => (
<Link key={idx} href={`#${h.id}`}> <Link rel="canonical" key={idx} href={`#${h.id}`}>
<Typography <Typography
variant="body2" variant="body2"
sx={{ sx={{
@ -171,10 +173,25 @@ export async function generateMetadata(
const keywords = item?.meta?.path || []; const keywords = item?.meta?.path || [];
const alias_keywords = item?.meta.aliases?.flat() || []; const alias_keywords = item?.meta.aliases?.flat() || [];
const title = item?.meta.path[item?.meta.path.length - 1]; // words?.forEach((word) => {
// console.log({ word });
// });
// console.log({ excerpt });
const name = item?.meta.path[item?.meta.path.length - 1];
const content = item?.content?.content || "";
const summary = await extractExcerpt(content, 35);
const description = await extractExcerpt(content, 200);
const title = `Nix ${name} - ${summary}`;
return { return {
// should be 20-70 characters
title, title,
description: item?.content?.content, // should be 70-160 characters
description,
authors: [ authors: [
{ name: "nixos", url: "https://nixos.org/" }, { name: "nixos", url: "https://nixos.org/" },
{ name: "nixpkgs", url: "https://github.com/NixOS/nixpkgs" }, { name: "nixpkgs", url: "https://github.com/NixOS/nixpkgs" },
@ -233,7 +250,7 @@ export default async function Page(props: { params: { path: string[] } }) {
idx === all.length - 1 ? ( idx === all.length - 1 ? (
<React.Fragment key={idx}> <React.Fragment key={idx}>
<meta data-pagefind-meta={`name:${attr}`} /> <meta data-pagefind-meta={`name:${attr}`} />
<Box component="h3" sx={{ display: "none" }}> <Box component="h2" sx={{ display: "none" }}>
{attr} {attr}
</Box> </Box>
</React.Fragment> </React.Fragment>
@ -348,7 +365,7 @@ export default async function Page(props: { params: { path: string[] } }) {
<Divider flexItem /> <Divider flexItem />
<Typography <Typography
variant="subtitle1" variant="subtitle1"
component={"h3"} component={"h4"}
sx={{ sx={{
color: "text.secondary", color: "text.secondary",
alignSelf: "center", alignSelf: "center",
@ -366,14 +383,16 @@ export default async function Page(props: { params: { path: string[] } }) {
This is a Functor This is a Functor
</Typography> </Typography>
<br /> <br />
<Link href="/md/tutorials/functors">Learn about functors</Link> <Link rel="canonical" href="/md/tutorials/functors">
Learn about functors
</Link>
</> </>
)} )}
{!!meta?.aliases?.length && ( {!!meta?.aliases?.length && (
<> <>
<Typography <Typography
variant="h5" variant="h5"
component={"div"} component={"h5"}
sx={{ color: "text.secondary" }} sx={{ color: "text.secondary" }}
> >
Aliases Aliases
@ -381,7 +400,9 @@ export default async function Page(props: { params: { path: string[] } }) {
<ul> <ul>
{meta?.aliases?.map((a) => ( {meta?.aliases?.map((a) => (
<li key={a.join(".")}> <li key={a.join(".")}>
<Link href={`/f/${a.join("/")}`}>{a.join(".")}</Link> <Link rel="canonical" href={`/f/${a.join("/")}`}>
{a.join(".")}
</Link>
</li> </li>
))} ))}
</ul> </ul>

View File

@ -6,7 +6,7 @@ import { ClientSideLayoutContext } from "@/components/ClientSideLayoutContext";
import { Metadata } from "next"; import { Metadata } from "next";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Noogle", title: "Noogle - Simply find Nix API reference documentation.",
description: description:
"Nix API reference. Includes nix, nixpkgs and nixos. Search nix functions within the nix ecosystem based on type, name, description, example, category and more.", "Nix API reference. Includes nix, nixpkgs and nixos. Search nix functions within the nix ecosystem based on type, name, description, example, category and more.",
creator: "@hsjobeki", creator: "@hsjobeki",

View File

@ -24,7 +24,7 @@ export default function Home() {
alignItems: "center", alignItems: "center",
}} }}
> >
<Link href="/md/release/2024-1" underline="none"> <Link rel="canonical" href="/md/release/2024-1" underline="none">
<Tooltip title="Whats new"> <Tooltip title="Whats new">
<Typography <Typography
variant="h1" variant="h1"

View File

@ -19,7 +19,7 @@ export const ListGroup = async (props: ListGroupProps) => {
const matter = await getMdxMeta(entry); const matter = await getMdxMeta(entry);
const { frontmatter } = matter.compiled; const { frontmatter } = matter.compiled;
return ( return (
<Link key={`${idx}`} href={`/ref/${entry.join("/")}`}> <Link rel="canonical" key={`${idx}`} href={`/ref/${entry.join("/")}`}>
<ListItem <ListItem
disablePadding disablePadding
disableGutters disableGutters

View File

@ -284,7 +284,11 @@ export function PagefindResults() {
secondaryTypographyProps={{ secondaryTypographyProps={{
variant: "body1", variant: "body1",
}} }}
primary={<Link href={`${url}`}>{meta.title}</Link>} primary={
<Link rel="canonical" href={`${url}`}>
{meta.title}
</Link>
}
secondary={ secondary={
<div dangerouslySetInnerHTML={{ __html: excerpt }} /> <div dangerouslySetInnerHTML={{ __html: excerpt }} />
} }

View File

@ -49,6 +49,7 @@ export const PositionLink = ({
<> <>
<Typography <Typography
variant="subtitle1" variant="subtitle1"
component={"div"}
sx={{ color: "text.secondary", pb: 2 }} sx={{ color: "text.secondary", pb: 2 }}
> >
This function is not declared in a .nix file This function is not declared in a .nix file
@ -56,6 +57,7 @@ export const PositionLink = ({
{!is_primop && ( {!is_primop && (
<Typography <Typography
variant="subtitle2" variant="subtitle2"
component={"div"}
sx={{ color: "text.secondary", pb: 2 }} sx={{ color: "text.secondary", pb: 2 }}
> >
This is very likely a bug in noogle please report this error. This is very likely a bug in noogle please report this error.
@ -143,7 +145,11 @@ export const PositionLink = ({
</Box> </Box>
)} )}
</Typography> </Typography>
<Typography variant="subtitle2" sx={{ color: "text.secondary" }}> <Typography
variant="subtitle2"
component={"div"}
sx={{ color: "text.secondary" }}
>
{contentPosition && {contentPosition &&
is_inherited && is_inherited &&
`(${content_meta?.path?.join(".")})`} `(${content_meta?.path?.join(".")})`}
@ -151,7 +157,7 @@ export const PositionLink = ({
</Box> </Box>
{!content?.content && ( {!content?.content && (
<> <>
<Typography variant="h5" sx={{ pt: 2 }}> <Typography variant="h5" component={"div"} sx={{ pt: 2 }}>
{"Contribute"} {"Contribute"}
</Typography> </Typography>
<Typography <Typography
@ -184,7 +190,6 @@ export const PositionLink = ({
secondary="Contribute to Noogle" secondary="Contribute to Noogle"
/> />
</ListItemButton> </ListItemButton>
{/* </Link> */}
</ListItem> </ListItem>
)} )}
</List> </List>

View File

@ -90,6 +90,7 @@ export const Navigation = ({
<Box sx={{ display: "flex", alignItems: "center" }}> <Box sx={{ display: "flex", alignItems: "center" }}>
{prev && ( {prev && (
<Link <Link
rel="canonical"
href={prev.url} href={prev.url}
sx={{ sx={{
my: 2, my: 2,
@ -111,6 +112,7 @@ export const Navigation = ({
{next && ( {next && (
<Link <Link
rel="canonical"
href={next.url} href={next.url}
sx={{ sx={{
ml: "auto", ml: "auto",

View File

@ -116,7 +116,10 @@ export function SearchResults() {
variant: "body1", variant: "body1",
}} }}
primary={ primary={
<Link href={`f/${meta.path.join("/")}`}> <Link
rel="canonical"
href={`f/${meta.path.join("/")}`}
>
{meta.title} {meta.title}
</Link> </Link>
} }

View File

@ -133,7 +133,11 @@ export const Filter = (props: FilterProps) => {
}} }}
> >
<Box sx={{ display: "flex", alignItems: "center", pr: 1 }}> <Box sx={{ display: "flex", alignItems: "center", pr: 1 }}>
<Typography variant="subtitle2" sx={{ color: "text.secondary" }}> <Typography
variant="subtitle2"
component="div"
sx={{ color: "text.secondary" }}
>
From From
</Typography> </Typography>
</Box> </Box>
@ -184,7 +188,11 @@ export const Filter = (props: FilterProps) => {
}} }}
> >
<Box sx={{ display: "flex", alignItems: "center", pr: 1 }}> <Box sx={{ display: "flex", alignItems: "center", pr: 1 }}>
<Typography variant="subtitle2" sx={{ color: "text.secondary" }}> <Typography
variant="subtitle2"
component="div"
sx={{ color: "text.secondary" }}
>
To To
</Typography> </Typography>
</Box> </Box>

View File

@ -46,6 +46,7 @@ export const Header = () => {
}} }}
> >
<Link <Link
rel="canonical"
href="/" href="/"
className={fira.className} className={fira.className}
sx={{ sx={{

View File

@ -34,7 +34,7 @@ export const Preview = (props: PreviewProps) => {
width: "100%", width: "100%",
}} }}
> >
<Link href={`/f/${meta.path.join("/")}`}> <Link rel="canonical" href={`/f/${meta.path.join("/")}`}>
<Typography <Typography
component="h3" component="h3"
variant="h4" variant="h4"

View File

@ -17,6 +17,7 @@ import remarkRehype from "remark-rehype";
import remarkUnlink from "remark-unlink"; import remarkUnlink from "remark-unlink";
import { unified } from "unified"; import { unified } from "unified";
import { rehypeExtractExcerpt } from "./excerpt";
/** /**
* Function to generate a set from a path in lodash style * Function to generate a set from a path in lodash style
@ -112,6 +113,23 @@ type Heading = {
id: string; id: string;
}; };
export const extractExcerpt = async (
content: string,
maxLength: number
): Promise<string> => {
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeExtractExcerpt, {
maxLength: maxLength,
ellipsis: " ...",
})
.use(rehypeStringify);
const result = await processor.process(content);
return result.data.excerpt as string;
};
export const extractHeadings = async (content: string): Promise<Heading[]> => { export const extractHeadings = async (content: string): Promise<Heading[]> => {
const processor = unified() const processor = unified()
.use(remarkParse) .use(remarkParse)