dark mode and light mode support
This commit is contained in:
@@ -4,7 +4,7 @@ export const Logo = () => {
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
id="svg166"
|
id="svg166"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
className="fill-action group-hover:fill-secondary transition-all ease-in duration-100 flex-no-shrink xl:w-12 xl:h-12 w-8 h-8"
|
className="fill-action group-hover:fill-primary dark:group-hover:fill-secondar transition-all ease-in duration-100 flex-no-shrink xl:w-12 xl:h-12 w-8 h-8"
|
||||||
viewBox="0 0 100 100"
|
viewBox="0 0 100 100"
|
||||||
>
|
>
|
||||||
<g id="167217677994600400">
|
<g id="167217677994600400">
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ export const Navbar = () => {
|
|||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="py-4 xl:px-10 px-4 flex flex-row justify-between sticky top-0 bg-gradient-dark z-50 border-b border-gradient-light">
|
<nav className="py-4 xl:px-10 px-4 flex flex-row justify-between sticky top-0 bg-slate-100 dark:bg-gradient-dark z-50 border-b dark:border-gradient-light border-gray-200">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
id="logo"
|
id="logo"
|
||||||
className="flex flex-row gap-2 items-center group"
|
className="flex flex-row gap-2 items-center group"
|
||||||
>
|
>
|
||||||
<Logo />
|
<Logo />
|
||||||
<div className="font-bold xl:text-4xl text-xl font-mono transition-all ease-in duration-100 text-action group-hover:text-secondary">
|
<div className="font-bold xl:text-4xl text-xl font-mono transition-all ease-in duration-100 text-action group-hover:text-primary dark:group-hover:text-secondary">
|
||||||
peroxy
|
peroxy
|
||||||
<span className="xl:text-sm text-xs">.dev</span>
|
<span className="xl:text-sm text-xs">.dev</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,7 +49,7 @@ export const Navbar = () => {
|
|||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
/>
|
/>
|
||||||
<motion.div
|
<motion.div
|
||||||
className={`z-40 absolute w-1/2 bg-blue-900
|
className={`z-40 absolute w-1/2 bg-blue-900 text-primary-text
|
||||||
right-0 top-0 px-10 py-6 h-full`}
|
right-0 top-0 px-10 py-6 h-full`}
|
||||||
initial={{ x: "100%" }}
|
initial={{ x: "100%" }}
|
||||||
animate={{ x: 0 }}
|
animate={{ x: 0 }}
|
||||||
|
|||||||
@@ -22,17 +22,19 @@ export const PostHeader = ({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="lg:text-5xl text-3xl font-bold mt-2">{title}</div>
|
<div className="lg:text-5xl text-3xl font-bold mt-2">{title}</div>
|
||||||
<div className="mt-2 text-gray-400">{description}</div>
|
<div className="mt-2 text-gray-600dark:text-gray-400">{description}</div>
|
||||||
<div className="mt-2 mb-10 flex lg:flex-row flex-col gap-2 xl:items-center">
|
<div className="mt-2 mb-10 flex lg:flex-row flex-col gap-2 items-center">
|
||||||
{author && (
|
{author && (
|
||||||
<div className="font-medium ">
|
<div className="font-medium ">
|
||||||
By{" "}
|
By{" "}
|
||||||
{authorLink && (
|
{authorLink && (
|
||||||
<Link href={authorLink} className="text-action">
|
<Link href={authorLink} className="dark:text-action text-primary">
|
||||||
@{author}
|
@{author}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{!authorLink && <span className="text-action">@{author}</span>}
|
{!authorLink && (
|
||||||
|
<span className="dark:text-action text-primary">@{author}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="text-sm font-medium text-gray-500 lg:before:content-['•'] lg:after:content-['•'] lg:before:pr-2 lg:after:pl-2">
|
<div className="text-sm font-medium text-gray-500 lg:before:content-['•'] lg:after:content-['•'] lg:before:pr-2 lg:after:pl-2">
|
||||||
|
|||||||
110
components/StyledMarkdown.tsx
Normal file
110
components/StyledMarkdown.tsx
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import rangeParser from "parse-numeric-range";
|
||||||
|
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
|
import tsx from "react-syntax-highlighter/dist/cjs/languages/prism/tsx";
|
||||||
|
import typescript from "react-syntax-highlighter/dist/cjs/languages/prism/typescript";
|
||||||
|
import scss from "react-syntax-highlighter/dist/cjs/languages/prism/scss";
|
||||||
|
import bash from "react-syntax-highlighter/dist/cjs/languages/prism/bash";
|
||||||
|
import markdown from "react-syntax-highlighter/dist/cjs/languages/prism/markdown";
|
||||||
|
import json from "react-syntax-highlighter/dist/cjs/languages/prism/json";
|
||||||
|
import { coldarkDark as defaulttheme } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||||
|
import { BiCopy } from "react-icons/bi";
|
||||||
|
import { Components } from "react-markdown";
|
||||||
|
import { generateSlug } from "../utils/general";
|
||||||
|
import ReactMarkdown from "react-markdown";
|
||||||
|
import remarkGfm from "remark-gfm";
|
||||||
|
SyntaxHighlighter.registerLanguage("tsx", tsx);
|
||||||
|
SyntaxHighlighter.registerLanguage("typescript", typescript);
|
||||||
|
SyntaxHighlighter.registerLanguage("scss", scss);
|
||||||
|
SyntaxHighlighter.registerLanguage("bash", bash);
|
||||||
|
SyntaxHighlighter.registerLanguage("markdown", markdown);
|
||||||
|
SyntaxHighlighter.registerLanguage("json", json);
|
||||||
|
|
||||||
|
export const StyledMarkdown = ({ html }: { html: string }) => {
|
||||||
|
const MarkdownComponents: Components = {
|
||||||
|
h3: (props: any) => {
|
||||||
|
const arr = props.children;
|
||||||
|
let heading = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i]?.type !== undefined) {
|
||||||
|
for (let j = 0; j < arr[i].props.children.length; j++) {
|
||||||
|
heading += arr[i]?.props?.children[0];
|
||||||
|
}
|
||||||
|
} else heading += arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const slug = generateSlug(heading);
|
||||||
|
return (
|
||||||
|
<h3 id={slug}>
|
||||||
|
<a href={`#${slug}`} {...props}></a>
|
||||||
|
</h3>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
code({ node, inline, className, ...props }: any) {
|
||||||
|
const match = /language-(\w+)/.exec(className || "");
|
||||||
|
const hasMeta = node?.data?.meta;
|
||||||
|
|
||||||
|
const applyHighlights: object = (applyHighlights: number) => {
|
||||||
|
if (hasMeta) {
|
||||||
|
const RE = /{([\d,-]+)}/;
|
||||||
|
const metadata = node.data.meta?.replace(/\s/g, "");
|
||||||
|
const strlineNumbers = RE?.test(metadata)
|
||||||
|
? // @ts-ignore
|
||||||
|
RE?.exec(metadata)[1]
|
||||||
|
: "0";
|
||||||
|
const highlightLines = rangeParser(strlineNumbers);
|
||||||
|
const highlight = highlightLines;
|
||||||
|
const data = highlight.includes(applyHighlights) ? "highlight" : null;
|
||||||
|
return { data };
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return match ? (
|
||||||
|
<div>
|
||||||
|
<div className="w-full">
|
||||||
|
<button
|
||||||
|
className="w-fit ml-2 important"
|
||||||
|
onClick={() => navigator.clipboard.writeText(props.children)}
|
||||||
|
>
|
||||||
|
<BiCopy />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
style={defaulttheme}
|
||||||
|
language={match[1]}
|
||||||
|
PreTag="div"
|
||||||
|
className="codeStyle"
|
||||||
|
showLineNumbers={true}
|
||||||
|
wrapLines={hasMeta ? true : false}
|
||||||
|
useInlineStyles={true}
|
||||||
|
lineProps={applyHighlights}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<code className={className} {...props} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="
|
||||||
|
prose
|
||||||
|
prose-code:font-mono prose-code:text-gray-100 prose-code:bg-gray-700 prose-code:p-1 prose-code:m-1 prose-code:rounded-md
|
||||||
|
prose-headings:text-gray-800 dark:prose-headings:text-primary-text prose-p:text-gray-600 dark:prose-p:text-gray-100
|
||||||
|
prose-img:w-full prose-img:h-auto xl:prose-img:max-h-96 prose-img:object-cover
|
||||||
|
prose-li text-gray-600 dark:prose-li:text-gray-300 prose-td:text-gray-600 dark:prose-td:text-gray-400
|
||||||
|
prose-a:text-primary dark:prose-a:text-action prose-strong:text-gray-900 dark:prose-strong:text-gray-50
|
||||||
|
dark:prose-hr:bg-gray-200 prose-hr:bg-gray-400
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<ReactMarkdown
|
||||||
|
components={MarkdownComponents}
|
||||||
|
remarkPlugins={[remarkGfm]}
|
||||||
|
children={html}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,36 +6,21 @@ import { MarkdownRenderingResult } from "../../types/types";
|
|||||||
import { MainLayout } from "../../layouts/MainLayout";
|
import { MainLayout } from "../../layouts/MainLayout";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { IoMdArrowRoundBack as BackIcon } from "react-icons/io";
|
import { IoMdArrowRoundBack as BackIcon } from "react-icons/io";
|
||||||
import ReactMarkdown from "react-markdown";
|
|
||||||
import { MarkdownComponents } from "../../utils/reactmarkdown";
|
|
||||||
import remarkGfm from "remark-gfm";
|
|
||||||
import { PostHeader } from "../../components/PostHeader";
|
import { PostHeader } from "../../components/PostHeader";
|
||||||
import { readingTime } from "../../utils/general";
|
import { readingTime } from "../../utils/general";
|
||||||
|
import { StyledMarkdown } from "../../components/StyledMarkdown";
|
||||||
|
|
||||||
export const BlogArticle = ({ frontMatter, html }: MarkdownRenderingResult) => {
|
export const BlogArticle = ({ frontMatter, html }: MarkdownRenderingResult) => {
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Link href="/blog">
|
<Link href="/blog">
|
||||||
<button className="flex flex-row items-center gap-2 text-secondary hover:text-secondary/50 transition-all ease-in duration-75">
|
<button className="flex flex-row items-center gap-2 text-primary hover:text-primary-dark dark:text-secondary dark:hover:text-secondary/50 transition-all ease-in duration-75">
|
||||||
<BackIcon />
|
<BackIcon />
|
||||||
<span>Go Back</span>
|
<span>Go Back</span>
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
<PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
|
<PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
|
||||||
<div
|
<StyledMarkdown html={html} />
|
||||||
className="
|
|
||||||
prose prose-code:font-mono prose-code:text-gray-100 prose-code:bg-gray-700
|
|
||||||
prose-code:p-1 prose-code:m-1 prose-code:rounded-md prose-headings:text-primary-text
|
|
||||||
prose-p:text-gray-100 prose-img:w-full prose-img:h-auto xl:prose-img:max-h-96
|
|
||||||
prose-img:object-cover prose-li:text-gray-300 prose-td:text-gray-400
|
|
||||||
prose-a:text-action prose-strong:text-gray-50"
|
|
||||||
>
|
|
||||||
<ReactMarkdown
|
|
||||||
components={MarkdownComponents}
|
|
||||||
remarkPlugins={[remarkGfm]}
|
|
||||||
children={html}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { GetServerSideProps } from "next";
|
import { GetServerSideProps } from "next";
|
||||||
import { MainLayout } from "../../layouts/MainLayout";
|
import { MainLayout } from "../../layouts/MainLayout";
|
||||||
import { Post, getAllBlogsFrontMatter } from "../../utils/markdown";
|
import { Post, getAllBlogsFrontMatter } from "../../utils/markdown";
|
||||||
import { FrontMatter } from "../../types/types";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { formatDate } from "../../utils/general";
|
import { formatDate } from "../../utils/general";
|
||||||
import { BasicArticleProps } from "../../components/PostHeader";
|
import { BasicArticleProps } from "../../components/PostHeader";
|
||||||
@@ -14,12 +13,14 @@ const BlogCard = ({
|
|||||||
slug: string;
|
slug: string;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="p-4 rounded-md border border-gray-700">
|
<div className="p-4 rounded-md border border-gray-200 shadow-md shadow-gray-200 dark:border-gray-700">
|
||||||
<div className="text-sm font-medium text-gray-500">
|
<div className="text-sm font-medium text-gray-500">
|
||||||
{formatDate(blog.date)}
|
{formatDate(blog.date)}
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-2xl font-bold">{blog.title}</h2>
|
<h2 className="text-2xl font-bold">{blog.title}</h2>
|
||||||
<p className="text-gray-400 text-lg">{blog.description}</p>
|
<p className="text-gray-600 dark:text-gray-400 text-lg">
|
||||||
|
{blog.description}
|
||||||
|
</p>
|
||||||
<Link href={`blog/${slug}`}>
|
<Link href={`blog/${slug}`}>
|
||||||
<button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white">
|
<button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white">
|
||||||
Read more
|
Read more
|
||||||
@@ -32,9 +33,9 @@ const BlogCard = ({
|
|||||||
const Blog = ({ posts }: { posts: Post[] }) => {
|
const Blog = ({ posts }: { posts: Post[] }) => {
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<h1 className="text-3xl font-bold">Blog</h1>
|
<h1 className="text-3xl font-bold text-gray-800">Blog</h1>
|
||||||
<div className="w-full h-0.5 bg-white/50 my-4 rounded-full" />
|
<div className="w-full h-0.5 bg-gray-200 dark:bg-gray-800 my-4 rounded-full" />
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{posts.map((post, index) => (
|
{posts.map((post, index) => (
|
||||||
<BlogCard
|
<BlogCard
|
||||||
key={index}
|
key={index}
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ import { MarkdownRenderingResult } from "../../types/types";
|
|||||||
import { MainLayout } from "../../layouts/MainLayout";
|
import { MainLayout } from "../../layouts/MainLayout";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { IoMdArrowRoundBack as BackIcon } from "react-icons/io";
|
import { IoMdArrowRoundBack as BackIcon } from "react-icons/io";
|
||||||
import ReactMarkdown from "react-markdown";
|
|
||||||
import remarkGfm from "remark-gfm";
|
|
||||||
import { readingTime } from "../../utils/general";
|
import { readingTime } from "../../utils/general";
|
||||||
import { MarkdownComponents } from "../../utils/reactmarkdown";
|
|
||||||
import { PostHeader } from "../../components/PostHeader";
|
import { PostHeader } from "../../components/PostHeader";
|
||||||
|
import { StyledMarkdown } from "../../components/StyledMarkdown";
|
||||||
|
|
||||||
export const ProjectArticle = ({
|
export const ProjectArticle = ({
|
||||||
frontMatter,
|
frontMatter,
|
||||||
@@ -19,27 +17,15 @@ export const ProjectArticle = ({
|
|||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Link href="/projects">
|
<Link href="/projects">
|
||||||
<button className="flex flex-row items-center gap-2 text-secondary hover:text-secondary/50 transition-all ease-in duration-75">
|
<button className="flex flex-row items-center gap-2 text-primary hover:text-primary-dark dark:text-secondary dark:hover:text-secondary/50 transition-all ease-in duration-75">
|
||||||
<BackIcon />
|
<BackIcon />
|
||||||
<span>Go Back</span>
|
<span>Go Back</span>
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
|
<PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
|
||||||
<div
|
|
||||||
className="
|
<StyledMarkdown html={html} />
|
||||||
prose prose-code:font-mono prose-code:text-gray-100 prose-code:bg-gray-700
|
|
||||||
prose-code:p-1 prose-code:m-1 prose-code:rounded-md prose-headings:text-primary-text
|
|
||||||
prose-p:text-gray-100 prose-img:w-full prose-img:h-auto xl:prose-img:max-h-96
|
|
||||||
prose-img:object-cover prose-li:text-gray-300 prose-td:text-gray-400
|
|
||||||
prose-a:text-action prose-strong:text-gray-50"
|
|
||||||
>
|
|
||||||
<ReactMarkdown
|
|
||||||
components={MarkdownComponents}
|
|
||||||
remarkPlugins={[remarkGfm]}
|
|
||||||
children={html}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,13 +13,15 @@ const ProjectCard = ({
|
|||||||
slug: string;
|
slug: string;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="p-4 rounded-md border border-gray-700 grid grid-cols-1 xl:grid-cols-2 items-center gap-4">
|
<div className="p-4 rounded-md border border-gray-200 shadow-md shadow-gray-200 dark:border-gray-700 grid grid-cols-1 xl:grid-cols-2 items-center gap-4">
|
||||||
<div className="order-last xl:order-1">
|
<div className="order-last xl:order-1">
|
||||||
<div className="text-sm font-medium text-gray-500">
|
<div className="text-sm font-medium text-gray-500">
|
||||||
{formatDate(project.date)}
|
{formatDate(project.date)}
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-2xl font-bold">{project.title}</h2>
|
<h2 className="text-2xl font-bold">{project.title}</h2>
|
||||||
<p className="text-gray-400 text-lg">{project.description}</p>
|
<p className="text-gray-600 dark:text-gray-400 text-lg">
|
||||||
|
{project.description}
|
||||||
|
</p>
|
||||||
<Link href={`project/${slug}`}>
|
<Link href={`project/${slug}`}>
|
||||||
<button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white">
|
<button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white">
|
||||||
Read more
|
Read more
|
||||||
@@ -40,8 +42,8 @@ const ProjectCard = ({
|
|||||||
const Projects = ({ posts }: { posts: Post[] }) => {
|
const Projects = ({ posts }: { posts: Post[] }) => {
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<h1 className="text-3xl font-bold">Projects</h1>
|
<h1 className="text-3xl font-bold text-gray-800">Projects</h1>
|
||||||
<div className="w-full h-0.5 bg-white/50 my-4 rounded-full" />
|
<div className="w-full h-0.5 bg-gray-200 dark:bg-gray-800 my-4 rounded-full" />
|
||||||
<div className="grid grid-cols-1 gap-4">
|
<div className="grid grid-cols-1 gap-4">
|
||||||
{posts.map((post, index) => (
|
{posts.map((post, index) => (
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@import "tailwindcss/utilities";
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply dark:bg-gradient-dark dark:text-primary-text bg-white text-gradient-dark xl:w-2/3 w-11/12 mx-auto;
|
@apply dark:bg-gradient-dark dark:text-primary-text bg-slate-100 text-gradient-dark xl:w-2/3 w-11/12 mx-auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose {
|
.prose {
|
||||||
@@ -11,9 +11,12 @@ body {
|
|||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
@apply dark:bg-slate-800 bg-slate-200 text-slate-800 !important;
|
||||||
|
}
|
||||||
|
|
||||||
pre > code {
|
pre > code {
|
||||||
background: transparent !important;
|
@apply bg-transparent text-gray-700 dark:text-slate-300 !important;
|
||||||
color: white !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeStyle > code {
|
.codeStyle > code {
|
||||||
@@ -25,9 +28,9 @@ pre > div > div > button > svg:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h3 > a {
|
h3 > a {
|
||||||
@apply cursor-pointer relative xl:text-4xl text-2xl text-primary-text decoration-transparent font-black uppercase !important;
|
@apply cursor-pointer relative xl:text-4xl text-2xl text-gray-800 dark:text-primary-text decoration-transparent font-black uppercase !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 > a:hover::before {
|
h3 > a:hover::before {
|
||||||
@apply content-['#'] absolute -left-8 text-gray-600;
|
@apply content-['#'] absolute -left-8 text-gray-300 dark:text-gray-600;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import { generateSlug } from "./general";
|
|
||||||
import rangeParser from "parse-numeric-range";
|
|
||||||
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
||||||
import tsx from "react-syntax-highlighter/dist/cjs/languages/prism/tsx";
|
|
||||||
import typescript from "react-syntax-highlighter/dist/cjs/languages/prism/typescript";
|
|
||||||
import scss from "react-syntax-highlighter/dist/cjs/languages/prism/scss";
|
|
||||||
import bash from "react-syntax-highlighter/dist/cjs/languages/prism/bash";
|
|
||||||
import markdown from "react-syntax-highlighter/dist/cjs/languages/prism/markdown";
|
|
||||||
import json from "react-syntax-highlighter/dist/cjs/languages/prism/json";
|
|
||||||
import { coldarkDark as defaulttheme } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
|
||||||
import { BiCopy } from "react-icons/bi";
|
|
||||||
import { Components } from "react-markdown";
|
|
||||||
SyntaxHighlighter.registerLanguage("tsx", tsx);
|
|
||||||
SyntaxHighlighter.registerLanguage("typescript", typescript);
|
|
||||||
SyntaxHighlighter.registerLanguage("scss", scss);
|
|
||||||
SyntaxHighlighter.registerLanguage("bash", bash);
|
|
||||||
SyntaxHighlighter.registerLanguage("markdown", markdown);
|
|
||||||
SyntaxHighlighter.registerLanguage("json", json);
|
|
||||||
|
|
||||||
export const MarkdownComponents: Components = {
|
|
||||||
h3: (props: any) => {
|
|
||||||
const arr = props.children;
|
|
||||||
let heading = "";
|
|
||||||
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
if (arr[i]?.type !== undefined) {
|
|
||||||
for (let j = 0; j < arr[i].props.children.length; j++) {
|
|
||||||
heading += arr[i]?.props?.children[0];
|
|
||||||
}
|
|
||||||
} else heading += arr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
const slug = generateSlug(heading);
|
|
||||||
return (
|
|
||||||
<h3 id={slug}>
|
|
||||||
<a href={`#${slug}`} {...props}></a>
|
|
||||||
</h3>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
code({ node, inline, className, ...props }: any) {
|
|
||||||
const match = /language-(\w+)/.exec(className || "");
|
|
||||||
const hasMeta = node?.data?.meta;
|
|
||||||
|
|
||||||
const applyHighlights: object = (applyHighlights: number) => {
|
|
||||||
if (hasMeta) {
|
|
||||||
const RE = /{([\d,-]+)}/;
|
|
||||||
const metadata = node.data.meta?.replace(/\s/g, "");
|
|
||||||
const strlineNumbers = RE?.test(metadata)
|
|
||||||
? // @ts-ignore
|
|
||||||
RE?.exec(metadata)[1]
|
|
||||||
: "0";
|
|
||||||
const highlightLines = rangeParser(strlineNumbers);
|
|
||||||
const highlight = highlightLines;
|
|
||||||
const data = highlight.includes(applyHighlights) ? "highlight" : null;
|
|
||||||
return { data };
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return match ? (
|
|
||||||
<div>
|
|
||||||
<div className="w-full">
|
|
||||||
<button
|
|
||||||
className="w-fit ml-2 important"
|
|
||||||
onClick={() => navigator.clipboard.writeText(props.children)}
|
|
||||||
>
|
|
||||||
<BiCopy className="hover:text-action important" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<SyntaxHighlighter
|
|
||||||
style={defaulttheme}
|
|
||||||
language={match[1]}
|
|
||||||
PreTag="div"
|
|
||||||
className="codeStyle bg-transparent"
|
|
||||||
showLineNumbers={true}
|
|
||||||
wrapLines={hasMeta ? true : false}
|
|
||||||
useInlineStyles={true}
|
|
||||||
lineProps={applyHighlights}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<code className={className} {...props} />
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user