mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-26 09:20:24 -05:00
* Remove light mode * Trim header * New front page initial * Get rid of build layout * Breadcrumbs * Desktop side nav * Overhaul colors * Add breadcrumbs * New sub nav style * Front page action buttons * Add back add new build button * Add articles page with icon * Minor Object damage page layout tweaks * Remove one unnecessary render from object damage * Fix wrong link in article page * Profile -> My Page in header * Log in/out buttons in front * Add drawings to front page * Remove unnecessary comment
95 lines
2.3 KiB
TypeScript
95 lines
2.3 KiB
TypeScript
import Markdown from "markdown-to-jsx";
|
|
import { Main } from "~/components/Main";
|
|
import {
|
|
json,
|
|
type SerializeFrom,
|
|
type LoaderArgs,
|
|
type MetaFunction,
|
|
} from "@remix-run/node";
|
|
import { useLoaderData } from "@remix-run/react";
|
|
import * as React from "react";
|
|
import { articleBySlug } from "~/modules/articles";
|
|
import invariant from "tiny-invariant";
|
|
import { makeTitle } from "~/utils/strings";
|
|
import {
|
|
articlePage,
|
|
articlePreviewUrl,
|
|
ARTICLES_MAIN_PAGE,
|
|
navIconUrl,
|
|
} from "~/utils/urls";
|
|
import type { SendouRouteHandle } from "~/utils/remix";
|
|
import { notFoundIfFalsy } from "~/utils/remix";
|
|
|
|
export const handle: SendouRouteHandle = {
|
|
breadcrumb: ({ match }) => {
|
|
const data = match.data as SerializeFrom<typeof loader>;
|
|
return [
|
|
{
|
|
imgPath: navIconUrl("articles"),
|
|
href: ARTICLES_MAIN_PAGE,
|
|
type: "IMAGE",
|
|
},
|
|
{
|
|
text: data.title,
|
|
href: articlePage(data.slug),
|
|
type: "TEXT",
|
|
},
|
|
];
|
|
},
|
|
};
|
|
|
|
export const meta: MetaFunction = (args) => {
|
|
invariant(args.params["slug"]);
|
|
const data = args.data as SerializeFrom<typeof loader> | null;
|
|
|
|
if (!data) return {};
|
|
|
|
const description = data.content.trim().split("\n")[0];
|
|
|
|
return {
|
|
title: makeTitle(data.title),
|
|
"og:title": data.title,
|
|
description,
|
|
"og:description": description,
|
|
"twitter:card": "summary_large_image",
|
|
"og:image": articlePreviewUrl(args.params["slug"]),
|
|
"og:type": "article",
|
|
"og:site_name": "sendou.ink",
|
|
};
|
|
};
|
|
|
|
export const loader = ({ params }: LoaderArgs) => {
|
|
invariant(params["slug"]);
|
|
|
|
const article = notFoundIfFalsy(articleBySlug(params["slug"]));
|
|
|
|
return json({ ...article, slug: params["slug"] });
|
|
};
|
|
|
|
export default function ArticlePage() {
|
|
const data = useLoaderData<typeof loader>();
|
|
return (
|
|
<Main>
|
|
<article className="article">
|
|
<h1>{data.title}</h1>
|
|
<div className="text-sm text-lighter">
|
|
by <Author /> • <time>{data.dateString}</time>
|
|
</div>
|
|
<Markdown options={{ wrapper: React.Fragment }}>
|
|
{data.content}
|
|
</Markdown>
|
|
</article>
|
|
</Main>
|
|
);
|
|
}
|
|
|
|
function Author() {
|
|
const data = useLoaderData<typeof loader>();
|
|
|
|
if (data.authorLink) {
|
|
return <a href={data.authorLink}>{data.author}</a>;
|
|
}
|
|
|
|
return <>{data.author}</>;
|
|
}
|