100 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Handlers, PageProps } from "$fresh/server.ts";
 | |
| import { MainLayout } from "@components/layouts/main.tsx";
 | |
| import { Article } from "@lib/resource/articles.ts";
 | |
| import { KMenu } from "@islands/KMenu.tsx";
 | |
| import { YoutubePlayer } from "@components/Youtube.tsx";
 | |
| import { HashTags } from "@components/HashTags.tsx";
 | |
| import { isYoutubeLink } from "@lib/string.ts";
 | |
| import { removeImage, renderMarkdown } from "@lib/documents.ts";
 | |
| import { RedirectSearchHandler } from "@islands/Search.tsx";
 | |
| import PageHero from "@components/PageHero.tsx";
 | |
| import { Star } from "@components/Stars.tsx";
 | |
| import { MetaTags } from "@components/MetaTags.tsx";
 | |
| import { fetchResource } from "@lib/resources.ts";
 | |
| 
 | |
| export const handler: Handlers<{ article: Article; session: unknown }> = {
 | |
|   async GET(_, ctx) {
 | |
|     const article = await fetchResource(`articles/${ctx.params.name}.md`);
 | |
|     if (!article) {
 | |
|       return ctx.renderNotFound();
 | |
|     }
 | |
|     return ctx.render({ article, session: ctx.state.session });
 | |
|   },
 | |
| };
 | |
| 
 | |
| export default function Greet(
 | |
|   props: PageProps<{ article: Article; session: Record<string, string> }>,
 | |
| ) {
 | |
|   const { article, session } = props.data;
 | |
| 
 | |
|   const { author = "", date = "", articleBody = "" } = (article?.content || {});
 | |
| 
 | |
|   const content = renderMarkdown(
 | |
|     removeImage(articleBody, article.content.image),
 | |
|   );
 | |
| 
 | |
|   console.log({ article });
 | |
| 
 | |
|   return (
 | |
|     <MainLayout
 | |
|       url={props.url}
 | |
|       title={`Article > ${article.content.headline}`}
 | |
|       context={article}
 | |
|     >
 | |
|       <RedirectSearchHandler />
 | |
|       <KMenu type="main" context={{ type: "article" }} />
 | |
|       <MetaTags resource={article} />
 | |
| 
 | |
|       <PageHero
 | |
|         image={article.content.image}
 | |
|         thumbnail={article.content.thumbnail}
 | |
|       >
 | |
|         <PageHero.Header>
 | |
|           <PageHero.BackLink href="/articles" />
 | |
|           {session && (
 | |
|             <PageHero.EditLink
 | |
|               href={`https://notes.max-richter.dev/resources/articles/${article.name}`}
 | |
|             />
 | |
|           )}
 | |
|         </PageHero.Header>
 | |
|         <PageHero.Footer>
 | |
|           <PageHero.Title link={article.content.url}>
 | |
|             {article.content.headline}
 | |
|           </PageHero.Title>
 | |
|           <PageHero.Subline
 | |
|             entries={[
 | |
|               author && {
 | |
|                 title: author,
 | |
|                 href: `/?q=${encodeURIComponent(author)}`,
 | |
|               },
 | |
|               date.toString(),
 | |
|             ]}
 | |
|           >
 | |
|             {article.content.rating && <Star rating={article.content.rating} />}
 | |
|           </PageHero.Subline>
 | |
|         </PageHero.Footer>
 | |
|       </PageHero>
 | |
|       {article.content?.tags?.length > 0 && (
 | |
|         <>
 | |
|           <br />
 | |
|           <HashTags tags={article.content.tags} />
 | |
|         </>
 | |
|       )}
 | |
| 
 | |
|       <div class="px-8 text-white mt-10">
 | |
|         {isYoutubeLink(article.content.url) && (
 | |
|           <YoutubePlayer link={article.content.url} />
 | |
|         )}
 | |
|         <pre
 | |
|           class="whitespace-break-spaces markdown-body"
 | |
|           data-color-mode="dark"
 | |
|           data-dark-theme="dark"
 | |
|           dangerouslySetInnerHTML={{ __html: content || "" }}
 | |
|         >
 | |
|           {content || ""}
 | |
|         </pre>
 | |
|       </div>
 | |
|     </MainLayout>
 | |
|   );
 | |
| }
 |