diff --git a/app/root.tsx b/app/root.tsx
index 0100364..1cb842d 100644
--- a/app/root.tsx
+++ b/app/root.tsx
@@ -1,9 +1,13 @@
import "@mantine/core/styles.css";
import {
+ Button as MantineButton,
+ Code,
ColorSchemeScript,
CSSVariablesResolver,
MantineProvider,
+ Stack,
+ Text,
Title,
} from "@mantine/core";
import { useLocalStorage, useToggle } from "@mantine/hooks";
@@ -14,6 +18,7 @@ import type {
MetaFunction,
} from "@remix-run/node";
import {
+ isRouteErrorResponse,
json,
Link,
Links,
@@ -24,9 +29,9 @@ import {
useRouteError,
} from "@remix-run/react";
-import { Button, Layout, Notification } from "~/components";
+import { Layout, Notification } from "~/components";
import styles from "~/styles/root.css?url";
-import { Status, status as httpStatus } from "~/utils";
+import { baseURL, Status, status as httpStatus } from "~/utils";
import ColorSchemeContext from "./styles/colorSchemeContext";
@@ -51,9 +56,9 @@ export const links: LinksFunction = () => [
rel: "license",
href: "https://github.com/blakenetz/portfolio/blob/master/LICENSE",
},
- { rel: "me", href: "https://blakenetzeband.com", type: "text/html" },
+ { rel: "me", href: baseURL, type: "text/html" },
{ rel: "me", href: "mailto:blake.netzeband@gmail.com" },
- { rel: "index", href: "https://blakenetzeband.com" },
+ { rel: "index", href: baseURL },
];
export const headers: HeadersFunction = () => ({
@@ -94,6 +99,11 @@ const resolver: CSSVariablesResolver = (theme) => {
export function ErrorBoundary() {
const error = useRouteError();
+ const status = isRouteErrorResponse(error) ? error.status : 520;
+ const statusText = isRouteErrorResponse(error)
+ ? error.statusText
+ : (error as Error)?.message ?? "Unknown";
+
if (process.env.NODE_ENV === "development") {
console.error("aw shit!", error);
}
@@ -103,6 +113,7 @@ export function ErrorBoundary() {
+
@@ -110,12 +121,25 @@ export function ErrorBoundary() {
-
- Crap. We hit an issue.
-
-
+
+
+
+ {status}
+
+ ... Crap. We hit an issue
+
+ This is all we know:
+ {statusText}
+
+
+ Send me home!
+
+
diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx
index 17f64f3..3bee393 100644
--- a/app/routes/_index.tsx
+++ b/app/routes/_index.tsx
@@ -1,10 +1,15 @@
import { Anchor, Flex, Text, Title } from "@mantine/core";
+import { MetaFunction } from "@remix-run/node";
import { Link } from "@remix-run/react";
import { Button } from "~/components";
import commonStyles from "~/styles/common.module.css";
import styles from "~/styles/index.module.css";
-import { cls } from "~/utils";
+import { cls, getCanonicalLink } from "~/utils";
+
+export const meta: MetaFunction = ({ location }) => {
+ return [getCanonicalLink(location)];
+};
export default function Index() {
return (
diff --git a/app/routes/blog.$post/route.tsx b/app/routes/blog.$post/route.tsx
index ed02dbc..403f15d 100644
--- a/app/routes/blog.$post/route.tsx
+++ b/app/routes/blog.$post/route.tsx
@@ -17,7 +17,7 @@ import { authenticator } from "~/server/authenticator.server";
import { getPost, postComment } from "~/server/blog.server";
import { PostModel } from "~/server/db.singleton.server";
import commonStyles from "~/styles/common.module.css";
-import { cls } from "~/utils";
+import { baseURL, cls, getCanonicalLink } from "~/utils";
import Comments from "./comments";
import components from "./components";
@@ -27,17 +27,18 @@ import Source from "./source";
export const meta: MetaFunction = ({ data, location }) => {
const { meta } = data as PostModel;
+ const url = new URL(location.pathname, baseURL);
+
+ const canonicalLink = getCanonicalLink(location);
const tags = [
{ title: ["BN", "Blog", meta.title].join(" | ") },
{ name: "description", content: meta.description },
+ canonicalLink,
/** @see https://www.linkedin.com/help/linkedin/answer/a521928/making-your-website-shareable-on-linkedin?lang=en */
{ property: "og:title", content: meta.title },
{ property: "og:description", content: meta.description },
- {
- property: "og:url",
- content: "https://blakenetzeband.com" + location.pathname,
- },
+ { property: "og:url", content: url.toString() },
{ property: "og:type", content: "article" },
];
diff --git a/app/routes/blog._index/route.tsx b/app/routes/blog._index/route.tsx
index f5de5ac..fa5049d 100644
--- a/app/routes/blog._index/route.tsx
+++ b/app/routes/blog._index/route.tsx
@@ -13,13 +13,14 @@ import { useState } from "react";
import { Card, SortControl } from "~/components";
import { inputName, sorts } from "~/server/blog";
import { getPosts } from "~/server/blog.server";
-import { getSearchString, validate } from "~/utils";
+import { getCanonicalLink, getSearchString, validate } from "~/utils";
import styles from "./blog.module.css";
-export const meta: MetaFunction = () => [
+export const meta: MetaFunction = ({ location }) => [
{ title: "BN | Blog" },
{ description: "My thoughts. some complete... others not... 😜" },
+ getCanonicalLink(location),
];
export async function loader({ request }: LoaderFunctionArgs) {
diff --git a/app/routes/projects/route.tsx b/app/routes/projects/route.tsx
index e808162..50cbfee 100644
--- a/app/routes/projects/route.tsx
+++ b/app/routes/projects/route.tsx
@@ -3,15 +3,18 @@ import { Form, Link, useLoaderData, useSubmit } from "@remix-run/react";
import { Button } from "~/components";
import { getRepos } from "~/server/projects.server";
-import { status } from "~/utils";
+import { getCanonicalLink, status } from "~/utils";
import styles from "./projects.module.css";
import Repos from "./repos";
-export const meta: MetaFunction = () => [
- { title: "BN | Projects" },
- { description: "My personal and work Github repositories" },
-];
+export const meta: MetaFunction = ({ location }) => {
+ return [
+ getCanonicalLink(location),
+ { title: "BN | Projects" },
+ { description: "My personal and work Github repositories" },
+ ];
+};
export async function loader({ request }: LoaderFunctionArgs) {
const repos = await getRepos(request);
diff --git a/app/utils/frontend.tsx b/app/utils/frontend.tsx
index 1114b5b..881089e 100644
--- a/app/utils/frontend.tsx
+++ b/app/utils/frontend.tsx
@@ -1,3 +1,18 @@
+import { MetaDescriptor } from "@remix-run/node";
+import { Location } from "@remix-run/react";
+
export function cls(...args: (string | boolean | undefined | null)[]) {
return args.filter(Boolean).join(" ").trim();
}
+
+export const baseURL = "https://blakenetzeband.com";
+
+export function getCanonicalLink(location: Location): MetaDescriptor {
+ const url = new URL(location.pathname, baseURL);
+
+ return {
+ tagName: "link",
+ rel: "canonical",
+ href: url.toString(),
+ };
+}
diff --git a/scripts/sitemap.ts b/scripts/sitemap.ts
index ad673dd..824d096 100644
--- a/scripts/sitemap.ts
+++ b/scripts/sitemap.ts
@@ -4,6 +4,8 @@ import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
import { format } from "date-fns";
import path from "path";
+import { baseURL } from "~/utils";
+
import { extractVFile, formatMeta } from "./util";
type NodeData = { [tagName: string]: string };
@@ -22,8 +24,8 @@ export default async function createSiteMap() {
const siteMapPath = path.resolve(".", "public/sitemap.xml");
const blogDir = path.resolve(".", "app/blog");
// trailing slash is important
- const urlBase = "https://blakenetzeband.com/";
- const blogBase = new URL("./blog", urlBase) + "/";
+
+ const blogBase = new URL("./blog", baseURL) + "/";
const siteMap = await fs.readFile(siteMapPath, "utf-8");
@@ -60,7 +62,7 @@ export default async function createSiteMap() {
// iterate over routes
["", "projects/", "blog/"].forEach((route) => {
- const loc = new URL(`./${route}`, urlBase).toString();
+ const loc = new URL(`./${route}`, baseURL).toString();
const today = formatDate();
const node = getByLocation(loc);