From 4df5503f3e06761a7096324f8e093ab4c1afefa7 Mon Sep 17 00:00:00 2001
From: eug-vs <eugene@eug-vs.xyz>
Date: Fri, 23 Sep 2022 13:14:11 +0300
Subject: feat: add emoji plugin

---
 src/Emoji.tsx           | 19 +++++++++++++++++++
 src/emojiPlugin.tsx     | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/pages/[...path].tsx | 35 ++++++++++++++++++++++++++---------
 src/pages/_app.tsx      |  4 ++--
 4 files changed, 95 insertions(+), 11 deletions(-)
 create mode 100644 src/Emoji.tsx
 create mode 100644 src/emojiPlugin.tsx

(limited to 'src')

diff --git a/src/Emoji.tsx b/src/Emoji.tsx
new file mode 100644
index 0000000..b928087
--- /dev/null
+++ b/src/Emoji.tsx
@@ -0,0 +1,19 @@
+import { FC } from 'react';
+import Image from 'next/future/image';
+
+interface Props {
+  children: string[];
+}
+
+const Emoji: FC<Props> = ({ children }) => {
+  const src = children[0];
+  return (
+    <Image
+      src={`/emoji/${src}`}
+      width={16}
+      alt={`${src}-emoji`}
+    />
+  );
+}
+
+export default Emoji;
diff --git a/src/emojiPlugin.tsx b/src/emojiPlugin.tsx
new file mode 100644
index 0000000..a408ed7
--- /dev/null
+++ b/src/emojiPlugin.tsx
@@ -0,0 +1,48 @@
+import _ from 'lodash';
+import { Node } from 'unist';
+import { visitParents } from 'unist-util-visit-parents'
+
+
+const emojiPlugin = (emojiFileNames: string[]) => () => {
+  const visitor = (node: any, ancestors: any[]) => {
+    const parent = _.last(ancestors);
+    const nodeIndex = parent?.children.indexOf(node);
+
+    const text: string = node.value;
+
+    const match = text?.match(/(:.*?:)/);
+
+    if (match && match.index !== undefined) {
+      const emoji = match[0]?.replaceAll(':', '') || '';
+      const src = emojiFileNames.find(fileName => fileName.match(`${emoji}.*`));
+
+      const beforeNode = {
+        type: 'text',
+        value: text.slice(0, match.index),
+      }
+
+      const emojiNode = {
+        type: 'element',
+        tagName: 'emoji',
+        children: [{
+          type: 'text',
+          value: src,
+        }],
+      }
+
+      const afterNode = {
+        type: 'text',
+        value: text.slice(match.index + emoji?.length + 2),
+      }
+
+      parent.children.splice(nodeIndex, 1, ...[beforeNode, emojiNode, afterNode])
+    }
+
+  }
+
+  return (tree: Node) => {
+    visitParents(tree, { type: 'text' }, visitor);
+  }
+}
+
+export default emojiPlugin;
diff --git a/src/pages/[...path].tsx b/src/pages/[...path].tsx
index 30fdcd6..9c7704e 100644
--- a/src/pages/[...path].tsx
+++ b/src/pages/[...path].tsx
@@ -1,12 +1,15 @@
 import _ from 'lodash';
-import type { GetStaticPropsContext, NextPage } from "next";
+import type { GetStaticPropsContext, NextPage } from 'next';
 import ReactMarkdown from 'react-markdown';
-import Head from "next/head";
-import deepReadDir from "../deepReadDir";
+import Head from 'next/head';
+import Emoji from '../Emoji';
+import deepReadDir from '../deepReadDir';
+import emojiPlugin from '../emojiPlugin';
 import fs from 'fs';
 
 
 const MARKDOWN_DIR = '../eug-vs-xyz/src';
+const EMOJI_DIR = 'public/emoji';
 
 const transformLinkURI = (uri: string): string => {
   return uri.match(/(.*)\.md/)?.[1] || uri;
@@ -15,9 +18,12 @@ const transformLinkURI = (uri: string): string => {
 export const getStaticProps = async (context: GetStaticPropsContext) => {
   const path = _.isArray(context.params?.path) && context.params?.path || [context.params?.path];
   const markdownSource = fs.readFileSync(`${MARKDOWN_DIR}/${path?.join('/')}.md`).toString();
+  const emojiFileNames = fs.readdirSync(EMOJI_DIR);
+
   return {
     props: {
       markdownSource,
+      emojiFileNames,
       path,
     }
   }
@@ -30,23 +36,34 @@ export const getStaticPaths = async () => {
     .filter(p => p)
     .map(p => p?.split('/'))
     .map(path => ({ params: { path } }));
-  console.log(paths);
   return {
     paths,
     fallback: false,
   }
 }
 
-const Page: NextPage = ({ markdownSource }: any) => {
+const Page: NextPage = ({ markdownSource, emojiFileNames }: any) => {
   return (
     <>
       <Head>
-        <title>Create T3 App</title>
-        <meta name="description" content="Generated by create-t3-app" />
-        <link rel="icon" href="/favicon.ico" />
+        <title>{`Eugene's Space`}</title>
+        <meta name="description" content="TODO" />
+        <link rel="icon" href="/icon-64.png" />
       </Head>
       <main>
-        <ReactMarkdown transformLinkUri={transformLinkURI}>{markdownSource}</ReactMarkdown>
+        <ReactMarkdown
+          children={markdownSource}
+          transformLinkUri={transformLinkURI}
+          rehypePlugins={[emojiPlugin(emojiFileNames)]}
+          components={{
+            emoji: Emoji,
+            h1: 'h2',
+            h2: 'h3',
+            h3: 'h4',
+            h4: 'h5',
+            h5: 'h6',
+          } as any}
+        />
       </main>
     </>
   );
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 191f276..a64a418 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,6 +1,6 @@
-import "../styles/globals.css";
+import '../styles/globals.css';
 import logo from '../../public/eug-vs.png';
-import type { AppProps } from "next/app";
+import type { AppProps } from 'next/app';
 import Image from 'next/future/image';
 
 function MyApp({ Component, pageProps }: AppProps) {
-- 
cgit v1.2.3