feat(UI): Adding linter and prettier for UI (#3156)

This commit is contained in:
Francisco Arceo 2025-08-14 15:58:43 -06:00 committed by GitHub
parent 61582f327c
commit e69acbafbf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 1452 additions and 1226 deletions

View file

@ -1,12 +1,12 @@
import React, { Suspense, useEffect, useState } from "react"
import Markdown from "react-markdown"
import remarkGfm from "remark-gfm"
import React, { Suspense, useEffect, useState } from "react";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { cn } from "@/lib/utils"
import { CopyButton } from "@/components/ui/copy-button"
import { cn } from "@/lib/utils";
import { CopyButton } from "@/components/ui/copy-button";
interface MarkdownRendererProps {
children: string
children: string;
}
export function MarkdownRenderer({ children }: MarkdownRendererProps) {
@ -16,34 +16,34 @@ export function MarkdownRenderer({ children }: MarkdownRendererProps) {
{children}
</Markdown>
</div>
)
);
}
interface HighlightedPre extends React.HTMLAttributes<HTMLPreElement> {
children: string
language: string
children: string;
language: string;
}
const HighlightedPre = React.memo(
({ children, language, ...props }: HighlightedPre) => {
const [tokens, setTokens] = useState<any[] | null>(null)
const [isSupported, setIsSupported] = useState(false)
const [tokens, setTokens] = useState<unknown[] | null>(null);
const [isSupported, setIsSupported] = useState(false);
useEffect(() => {
let mounted = true
let mounted = true;
const loadAndHighlight = async () => {
try {
const { codeToTokens, bundledLanguages } = await import("shiki")
const { codeToTokens, bundledLanguages } = await import("shiki");
if (!mounted) return
if (!mounted) return;
if (!(language in bundledLanguages)) {
setIsSupported(false)
return
setIsSupported(false);
return;
}
setIsSupported(true)
setIsSupported(true);
const { tokens: highlightedTokens } = await codeToTokens(children, {
lang: language as keyof typeof bundledLanguages,
@ -52,31 +52,31 @@ const HighlightedPre = React.memo(
light: "github-light",
dark: "github-dark",
},
})
});
if (mounted) {
setTokens(highlightedTokens)
setTokens(highlightedTokens);
}
} catch (error) {
} catch {
if (mounted) {
setIsSupported(false)
setIsSupported(false);
}
}
}
};
loadAndHighlight()
loadAndHighlight();
return () => {
mounted = false
}
}, [children, language])
mounted = false;
};
}, [children, language]);
if (!isSupported) {
return <pre {...props}>{children}</pre>
return <pre {...props}>{children}</pre>;
}
if (!tokens) {
return <pre {...props}>{children}</pre>
return <pre {...props}>{children}</pre>;
}
return (
@ -89,7 +89,7 @@ const HighlightedPre = React.memo(
const style =
typeof token.htmlStyle === "string"
? undefined
: token.htmlStyle
: token.htmlStyle;
return (
<span
@ -99,7 +99,7 @@ const HighlightedPre = React.memo(
>
{token.content}
</span>
)
);
})}
</span>
{lineIndex !== tokens.length - 1 && "\n"}
@ -107,15 +107,15 @@ const HighlightedPre = React.memo(
))}
</code>
</pre>
)
);
}
)
HighlightedPre.displayName = "HighlightedCode"
);
HighlightedPre.displayName = "HighlightedCode";
interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {
children: React.ReactNode
className?: string
language: string
children: React.ReactNode;
className?: string;
language: string;
}
const CodeBlock = ({
@ -127,12 +127,12 @@ const CodeBlock = ({
const code =
typeof children === "string"
? children
: childrenTakeAllStringContents(children)
: childrenTakeAllStringContents(children);
const preClass = cn(
"overflow-x-scroll rounded-md border bg-background/50 p-4 font-mono text-sm [scrollbar-width:none]",
className
)
);
return (
<div className="group/code relative mb-4">
@ -152,27 +152,27 @@ const CodeBlock = ({
<CopyButton content={code} copyMessage="Copied code to clipboard" />
</div>
</div>
)
}
);
};
function childrenTakeAllStringContents(element: any): string {
function childrenTakeAllStringContents(element: unknown): string {
if (typeof element === "string") {
return element
return element;
}
if (element?.props?.children) {
let children = element.props.children
const children = element.props.children;
if (Array.isArray(children)) {
return children
.map((child) => childrenTakeAllStringContents(child))
.join("")
.map(child => childrenTakeAllStringContents(child))
.join("");
} else {
return childrenTakeAllStringContents(children)
return childrenTakeAllStringContents(children);
}
}
return ""
return "";
}
const COMPONENTS = {
@ -184,8 +184,14 @@ const COMPONENTS = {
strong: withClass("strong", "font-semibold"),
a: withClass("a", "text-primary underline underline-offset-2"),
blockquote: withClass("blockquote", "border-l-2 border-primary pl-4"),
code: ({ children, className, node, ...rest }: any) => {
const match = /language-(\w+)/.exec(className || "")
code: ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
const match = /language-(\w+)/.exec(className || "");
return match ? (
<CodeBlock className={className} language={match[1]} {...rest}>
{children}
@ -199,9 +205,9 @@ const COMPONENTS = {
>
{children}
</code>
)
);
},
pre: ({ children }: any) => children,
pre: ({ children }: { children: React.ReactNode }) => children,
ol: withClass("ol", "list-decimal space-y-2 pl-6"),
ul: withClass("ul", "list-disc space-y-2 pl-6"),
li: withClass("li", "my-1.5"),
@ -220,14 +226,14 @@ const COMPONENTS = {
tr: withClass("tr", "m-0 border-t p-0 even:bg-muted"),
p: withClass("p", "whitespace-pre-wrap"),
hr: withClass("hr", "border-foreground/20"),
}
};
function withClass(Tag: keyof JSX.IntrinsicElements, classes: string) {
const Component = ({ node, ...props }: any) => (
const Component = ({ ...props }: Record<string, unknown>) => (
<Tag className={classes} {...props} />
)
Component.displayName = Tag
return Component
);
Component.displayName = Tag;
return Component;
}
export default MarkdownRenderer
export default MarkdownRenderer;