mirror of
https://git.aramjonghu.dev/AramJonghu/aramjonghu-site.git
synced 2026-09-06 23:33:30 +02:00
chore(nesting): reduced nesting
This commit is contained in:
@@ -52,7 +52,10 @@ export default function Header({ theme }: HeaderProps) {
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button className="ui-btn ui-btn:hover text-lg font-[NerdFontSymbols]" onClick={toggleTheme}>
|
<button
|
||||||
|
className="ui-btn ui-btn:hover text-lg font-[NerdFontSymbols]"
|
||||||
|
onClick={toggleTheme}
|
||||||
|
>
|
||||||
{currentTheme === "macchiato" ? "" : ""}
|
{currentTheme === "macchiato" ? "" : ""}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
useEffect,
|
useEffect,
|
||||||
useRef,
|
|
||||||
useState,
|
useState,
|
||||||
useMemo,
|
useMemo,
|
||||||
type ComponentPropsWithoutRef,
|
type ComponentPropsWithoutRef,
|
||||||
@@ -12,6 +11,25 @@ import rehypeRaw from "rehype-raw";
|
|||||||
import rehypeSanitize from "rehype-sanitize";
|
import rehypeSanitize from "rehype-sanitize";
|
||||||
import highlighter from "../utils/highlighter";
|
import highlighter from "../utils/highlighter";
|
||||||
|
|
||||||
|
function CopyButton({ code }: { code: string }): ReactElement {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
const btn = e.currentTarget;
|
||||||
|
navigator.clipboard.writeText(code).then(() => {
|
||||||
|
btn.textContent = "Copied!";
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.textContent = "\uf0c5";
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
className="absolute top-1 right-1 px-2 py-1 text-base font-mono text-ctp-subtext0 hover:text-ctp-green transition-colors cursor-pointer select-none z-10 font-[NerdFontSymbols]"
|
||||||
|
>
|
||||||
|
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const toRawUrl = (repoUrl: string): string => {
|
const toRawUrl = (repoUrl: string): string => {
|
||||||
if (!repoUrl) return repoUrl;
|
if (!repoUrl) return repoUrl;
|
||||||
|
|
||||||
@@ -112,6 +130,200 @@ export default function MdProcessor({
|
|||||||
const loading = useRemote && fetchState.url !== repoUrl;
|
const loading = useRemote && fetchState.url !== repoUrl;
|
||||||
const displayContent = directContent ?? fetchState.content;
|
const displayContent = directContent ?? fetchState.content;
|
||||||
|
|
||||||
|
const markdownComponents = {
|
||||||
|
code({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: ComponentPropsWithoutRef<"code">): ReactElement {
|
||||||
|
const isBlock =
|
||||||
|
className ||
|
||||||
|
(typeof children === "string" && children.includes("\n"));
|
||||||
|
|
||||||
|
if (isBlock) {
|
||||||
|
return (
|
||||||
|
<code className="text-sm" {...props}>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<code
|
||||||
|
className="bg-ctp-mantle px-1.5 py-0.5 rounded text-sm font-mono"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
pre({ children }: ComponentPropsWithoutRef<"pre">): ReactElement {
|
||||||
|
const codeChild = Array.isArray(children) ? children[0] : children;
|
||||||
|
|
||||||
|
let lang = "";
|
||||||
|
let code = "";
|
||||||
|
|
||||||
|
if (
|
||||||
|
codeChild &&
|
||||||
|
typeof codeChild === "object" &&
|
||||||
|
"props" in codeChild
|
||||||
|
) {
|
||||||
|
const el = codeChild as {
|
||||||
|
props: { className?: string; children?: string };
|
||||||
|
};
|
||||||
|
const cls = el.props?.className;
|
||||||
|
const match = cls?.match(/language-(\w+)/);
|
||||||
|
if (match) lang = match[1];
|
||||||
|
if (typeof el.props?.children === "string") {
|
||||||
|
code = el.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const highlighted =
|
||||||
|
lang && code
|
||||||
|
? highlighter.codeToHtml(code, {
|
||||||
|
lang,
|
||||||
|
themes: {
|
||||||
|
dark: "catppuccin-macchiato",
|
||||||
|
light: "catppuccin-latte",
|
||||||
|
},
|
||||||
|
defaultColor: false,
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (highlighted) {
|
||||||
|
return (
|
||||||
|
<div className="relative border-2 border-ctp-text/50 rounded-md overflow-hidden my-6 bg-ctp-base">
|
||||||
|
{lang && (
|
||||||
|
<span className="absolute top-0 left-0 px-2 py-1 text-xs font-mono text-ctp-mauve">
|
||||||
|
{lang}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<CopyButton code={code} />
|
||||||
|
<div
|
||||||
|
className={`overflow-x-auto text-sm p-4 ${lang ? "pt-7" : ""}`}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: highlighted,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative border-2 border-ctp-text/50 rounded-md overflow-hidden my-6 bg-ctp-base">
|
||||||
|
<CopyButton code={code} />
|
||||||
|
<pre className="overflow-x-auto text-sm p-4 m-0">
|
||||||
|
{children}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
h1({ children }: ComponentPropsWithoutRef<"h1">): ReactElement {
|
||||||
|
return (
|
||||||
|
<h1 className="text-3xl font-bold text-ctp-mauve mt-8 mb-4 border-b pb-2 border-ctp-green">
|
||||||
|
{children}
|
||||||
|
</h1>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
h2({ children }: ComponentPropsWithoutRef<"h2">): ReactElement {
|
||||||
|
return (
|
||||||
|
<h2 className="text-2xl font-bold text-ctp-lavender mt-8 mb-4 border-b pb-2 border-ctp-green">
|
||||||
|
{children}
|
||||||
|
</h2>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
h3({ children }: ComponentPropsWithoutRef<"h3">): ReactElement {
|
||||||
|
return (
|
||||||
|
<h3 className="text-xl font-bold text-ctp-lavender mt-5 mb-3">
|
||||||
|
{children}
|
||||||
|
</h3>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
p({ children }: ComponentPropsWithoutRef<"p">): ReactElement {
|
||||||
|
return <p className="mb-4 text-ctp-text">{children}</p>;
|
||||||
|
},
|
||||||
|
|
||||||
|
ul({ children }: ComponentPropsWithoutRef<"ul">): ReactElement {
|
||||||
|
return <ul className="list-disc pl-6 mb-4">{children}</ul>;
|
||||||
|
},
|
||||||
|
|
||||||
|
ol({ children }: ComponentPropsWithoutRef<"ol">): ReactElement {
|
||||||
|
return <ol className="list-decimal pl-6 mb-4">{children}</ol>;
|
||||||
|
},
|
||||||
|
|
||||||
|
li({ children }: ComponentPropsWithoutRef<"li">): ReactElement {
|
||||||
|
return <li className="mb-1">{children}</li>;
|
||||||
|
},
|
||||||
|
|
||||||
|
a({ children, href }: ComponentPropsWithoutRef<"a">): ReactElement {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="hover:underline text-ctp-green"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
blockquote({
|
||||||
|
children,
|
||||||
|
}: ComponentPropsWithoutRef<"blockquote">): ReactElement {
|
||||||
|
return (
|
||||||
|
<blockquote className="border-l-4 border-ctp-text pl-4 py-1 mb-4 bg-ctp-mantle rounded-r-lg">
|
||||||
|
{children}
|
||||||
|
</blockquote>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
table({ children }: ComponentPropsWithoutRef<"table">): ReactElement {
|
||||||
|
return (
|
||||||
|
<div className="overflow-x-auto my-4">
|
||||||
|
<table className="w-full border-collapse border border-ctp-overlay0">
|
||||||
|
{children}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
th({ children }: ComponentPropsWithoutRef<"th">): ReactElement {
|
||||||
|
return (
|
||||||
|
<th className="border border-ctp-overlay0 bg-ctp-surface0 px-4 py-2 text-left font-bold text-ctp-lavender">
|
||||||
|
{children}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
td({ children }: ComponentPropsWithoutRef<"td">): ReactElement {
|
||||||
|
return (
|
||||||
|
<td className="border border-ctp-overlay0 px-4 py-2 text-ctp-text">
|
||||||
|
{children}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
img({ src, alt }: ComponentPropsWithoutRef<"img">): ReactElement {
|
||||||
|
const resolved = resolveImageSrc(src || "", base);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src={resolved}
|
||||||
|
alt={alt}
|
||||||
|
className="max-w-full h-auto rounded-md my-4 shadow-sm border-2 border-ctp-text"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-w-4xl mx-auto p-4 md:p-8 bg-ctp-mantle rounded-xl shadow-sm border border-ctp-text">
|
<div className="w-full max-w-4xl mx-auto p-4 md:p-8 bg-ctp-mantle rounded-xl shadow-sm border border-ctp-text">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
@@ -125,274 +337,7 @@ export default function MdProcessor({
|
|||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
rehypePlugins={[rehypeRaw, rehypeSanitize]}
|
rehypePlugins={[rehypeRaw, rehypeSanitize]}
|
||||||
components={{
|
components={markdownComponents}
|
||||||
code({
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
}: ComponentPropsWithoutRef<"code">): ReactElement {
|
|
||||||
const isBlock =
|
|
||||||
className ||
|
|
||||||
(typeof children === "string" &&
|
|
||||||
children.includes("\n"));
|
|
||||||
|
|
||||||
if (isBlock) {
|
|
||||||
return (
|
|
||||||
<code className="text-sm" {...props}>
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<code
|
|
||||||
className="bg-ctp-mantle px-1.5 py-0.5 rounded text-sm font-mono"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
pre({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"pre">): ReactElement {
|
|
||||||
const codeChild = Array.isArray(children)
|
|
||||||
? children[0]
|
|
||||||
: children;
|
|
||||||
|
|
||||||
let lang = "";
|
|
||||||
let code = "";
|
|
||||||
|
|
||||||
if (
|
|
||||||
codeChild &&
|
|
||||||
typeof codeChild === "object" &&
|
|
||||||
"props" in codeChild
|
|
||||||
) {
|
|
||||||
const el = codeChild as {
|
|
||||||
props: {
|
|
||||||
className?: string;
|
|
||||||
children?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const cls = el.props?.className;
|
|
||||||
const match = cls?.match(/language-(\w+)/);
|
|
||||||
if (match) lang = match[1];
|
|
||||||
if (
|
|
||||||
typeof el.props?.children === "string"
|
|
||||||
) {
|
|
||||||
code = el.props.children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const highlighted =
|
|
||||||
lang && code
|
|
||||||
? highlighter.codeToHtml(code, {
|
|
||||||
lang,
|
|
||||||
themes: {
|
|
||||||
dark: "catppuccin-macchiato",
|
|
||||||
light: "catppuccin-latte",
|
|
||||||
},
|
|
||||||
defaultColor: false,
|
|
||||||
})
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const copyRef = useRef<HTMLButtonElement>(null);
|
|
||||||
|
|
||||||
if (highlighted) {
|
|
||||||
return (
|
|
||||||
<div className="relative border-2 border-ctp-text/50 rounded-md overflow-hidden my-6 bg-ctp-base">
|
|
||||||
{lang && (
|
|
||||||
<span className="absolute top-0 left-0 px-2 py-1 text-xs font-mono text-ctp-mauve">
|
|
||||||
{lang}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
ref={copyRef}
|
|
||||||
onClick={() => {
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(code)
|
|
||||||
.then(() => {
|
|
||||||
if (copyRef.current) {
|
|
||||||
copyRef.current.textContent =
|
|
||||||
"Copied!";
|
|
||||||
setTimeout(
|
|
||||||
() => {
|
|
||||||
if (
|
|
||||||
copyRef.current
|
|
||||||
)
|
|
||||||
copyRef.current.textContent =
|
|
||||||
"\uf0c5";
|
|
||||||
},
|
|
||||||
1500,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
className="absolute top-1 right-1 px-2 py-1 text-base font-mono text-ctp-subtext0 hover:text-ctp-green transition-colors cursor-pointer select-none z-10 font-[NerdFontSymbols]"
|
|
||||||
>
|
|
||||||
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
className={`overflow-x-auto text-sm p-4 ${lang ? "pt-7" : ""}`}
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: highlighted,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<pre className="overflow-x-auto text-sm p-4 bg-ctp-base m-0 border-2 border-ctp-text/50 rounded-md my-6">
|
|
||||||
{children}
|
|
||||||
</pre>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
h1({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"h1">): ReactElement {
|
|
||||||
return (
|
|
||||||
<h1 className="text-3xl font-bold text-ctp-mauve mt-8 mb-4 border-b pb-2 border-ctp-green">
|
|
||||||
{children}
|
|
||||||
</h1>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
h2({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"h2">): ReactElement {
|
|
||||||
return (
|
|
||||||
<h2 className="text-2xl font-bold text-ctp-lavender mt-8 mb-4 border-b pb-2 border-ctp-green">
|
|
||||||
{children}
|
|
||||||
</h2>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
h3({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"h3">): ReactElement {
|
|
||||||
return (
|
|
||||||
<h3 className="text-xl font-bold text-ctp-lavender mt-5 mb-3">
|
|
||||||
{children}
|
|
||||||
</h3>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
p({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"p">): ReactElement {
|
|
||||||
return (
|
|
||||||
<p className="mb-4 text-ctp-text">
|
|
||||||
{children}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
ul({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"ul">): ReactElement {
|
|
||||||
return (
|
|
||||||
<ul className="list-disc pl-6 mb-4">
|
|
||||||
{children}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
ol({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"ol">): ReactElement {
|
|
||||||
return (
|
|
||||||
<ol className="list-decimal pl-6 mb-4">
|
|
||||||
{children}
|
|
||||||
</ol>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
li({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"li">): ReactElement {
|
|
||||||
return <li className="mb-1">{children}</li>;
|
|
||||||
},
|
|
||||||
|
|
||||||
a({
|
|
||||||
children,
|
|
||||||
href,
|
|
||||||
}: ComponentPropsWithoutRef<"a">): ReactElement {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
href={href}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="hover:underline text-ctp-green"
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
blockquote({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"blockquote">): ReactElement {
|
|
||||||
return (
|
|
||||||
<blockquote className="border-l-4 border-ctp-text pl-4 py-1 mb-4 bg-ctp-mantle rounded-r-lg">
|
|
||||||
{children}
|
|
||||||
</blockquote>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
table({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"table">): ReactElement {
|
|
||||||
return (
|
|
||||||
<div className="overflow-x-auto my-4">
|
|
||||||
<table className="w-full border-collapse border border-ctp-overlay0">
|
|
||||||
{children}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
th({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"th">): ReactElement {
|
|
||||||
return (
|
|
||||||
<th className="border border-ctp-overlay0 bg-ctp-surface0 px-4 py-2 text-left font-bold text-ctp-lavender">
|
|
||||||
{children}
|
|
||||||
</th>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
td({
|
|
||||||
children,
|
|
||||||
}: ComponentPropsWithoutRef<"td">): ReactElement {
|
|
||||||
return (
|
|
||||||
<td className="border border-ctp-overlay0 px-4 py-2 text-ctp-text">
|
|
||||||
{children}
|
|
||||||
</td>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
img({
|
|
||||||
src,
|
|
||||||
alt,
|
|
||||||
}: ComponentPropsWithoutRef<"img">): ReactElement {
|
|
||||||
const resolved = resolveImageSrc(
|
|
||||||
src || "",
|
|
||||||
base,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<img
|
|
||||||
src={resolved}
|
|
||||||
alt={alt}
|
|
||||||
className="max-w-full h-auto rounded-md my-4 shadow-sm border-2 border-ctp-text"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{displayContent}
|
{displayContent}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
|||||||
Reference in New Issue
Block a user