Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export const CodeSegment: React.FC<CodeSegmentProps> = ({
<>
<CodeClient
code={code}
loadingClassName="min-h-[450px] rounded-none border-none"
className="rounded-none border-none"
lang={
isInstallCommand
Expand Down
50 changes: 50 additions & 0 deletions apps/dashboard/src/@/components/ui/code/CodeBlockContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";

import { cn } from "@/lib/utils";
import { useClipboard } from "hooks/useClipboard";
import { CheckIcon, CopyIcon } from "lucide-react";
import { ScrollShadow } from "../ScrollShadow/ScrollShadow";
import { Button } from "../button";

export function CodeBlockContainer(props: {
codeToCopy: string;
children: React.ReactNode;
className?: string;
scrollableClassName?: string;
copyButtonClassName?: string;
}) {
const { hasCopied, onCopy } = useClipboard(props.codeToCopy);

return (
<div
className={cn(
"group relative max-w-full overflow-hidden rounded-lg border border-border bg-background",
props.className,
)}
>
<ScrollShadow
scrollableClassName={cn("p-4", props.scrollableClassName)}
className="text-xs md:text-sm [&_*]:leading-relaxed"
shadowColor="hsl(var(--muted))"
>
{props.children}
</ScrollShadow>

<Button
size="sm"
variant="outline"
onClick={onCopy}
className={cn(
"absolute top-3.5 right-3.5 h-auto bg-background p-2",
props.copyButtonClassName,
)}
>
{hasCopied ? (
<CheckIcon className="size-3 text-green-500" />
) : (
<CopyIcon className="size-3 text-muted-foreground" />
)}
</Button>
</div>
);
}
69 changes: 11 additions & 58 deletions apps/dashboard/src/@/components/ui/code/RenderCode.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,23 @@
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { Button } from "@/components/ui/button";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { CheckIcon, CopyIcon } from "lucide-react";
import { useState } from "react";
import { CodeBlockContainer } from "./CodeBlockContainer";

export function RenderCode(props: {
code: string;
html: string;
className?: string;
scrollableClassName?: string;
copyButtonClassName?: string;
}) {
return (
<div
className={cn(
"group relative max-w-full overflow-hidden rounded-lg border border-border bg-background",
props.className,
)}
<CodeBlockContainer
codeToCopy={props.code}
className={props.className}
copyButtonClassName={props.copyButtonClassName}
scrollableClassName={props.scrollableClassName}
>
<ScrollShadow
scrollableClassName={cn("p-4", props.scrollableClassName)}
className="text-xs md:text-sm [&_*]:leading-relaxed"
shadowColor="hsl(var(--muted))"
>
<div
// biome-ignore lint/security/noDangerouslySetInnerHtml: we know what we're doing here
dangerouslySetInnerHTML={{ __html: props.html }}
/>
</ScrollShadow>
<CopyButton
text={props.code}
iconClassName="size-3"
className="absolute top-4 right-4 z-10 border border-border bg-background p-2 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
<div
// biome-ignore lint/security/noDangerouslySetInnerHtml: we know what we're doing here
dangerouslySetInnerHTML={{ __html: props.html }}
/>
</div>
);
}

function CopyButton(props: {
text: string;
className?: string;
iconClassName?: string;
}) {
const [isCopied, setIsCopied] = useState(false);
return (
<ToolTipLabel label="Copy">
<Button
variant="ghost"
aria-label="Copy"
className={cn("h-auto w-auto p-1", props.className)}
onClick={() => {
navigator.clipboard.writeText(props.text);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 1000);
}}
>
{isCopied ? (
<CheckIcon
className={cn("size-4 text-green-500", props.iconClassName)}
/>
) : (
<CopyIcon
className={cn("size-4 text-muted-foreground", props.iconClassName)}
/>
)}
</Button>
</ToolTipLabel>
</CodeBlockContainer>
);
}
23 changes: 10 additions & 13 deletions apps/dashboard/src/@/components/ui/code/code.client.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
"use client";

import { cn } from "@/lib/utils";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import type { BundledLanguage } from "shiki";
import { Spinner } from "../../ui/Spinner/Spinner";
import { RenderCode } from "./RenderCode";
import { getCodeHtml } from "./getCodeHtml";
import { PlainTextCodeBlock } from "./plaintext-code";

export type CodeProps = {
code: string;
lang: BundledLanguage;
className?: string;
scrollableClassName?: string;
loadingClassName?: string;
keepPreviousDataOnCodeChange?: boolean;
copyButtonClassName?: string;
};

export const CodeClient: React.FC<CodeProps> = ({
code,
lang,
className,
scrollableClassName,
loadingClassName,
keepPreviousDataOnCodeChange = false,
copyButtonClassName,
}) => {
const codeQuery = useQuery({
queryKey: ["html", code],
Expand All @@ -35,14 +33,12 @@ export const CodeClient: React.FC<CodeProps> = ({

if (!codeQuery.data) {
return (
<div
className={cn(
"flex min-h-[200px] items-center justify-center rounded-lg border border-border",
loadingClassName,
)}
>
<Spinner className="size-8" />
</div>
<PlainTextCodeBlock
code={code}
className={className}
scrollableClassName={scrollableClassName}
copyButtonClassName={copyButtonClassName}
/>
);
}

Expand All @@ -52,6 +48,7 @@ export const CodeClient: React.FC<CodeProps> = ({
html={codeQuery.data.html}
className={className}
scrollableClassName={scrollableClassName}
copyButtonClassName={copyButtonClassName}
/>
);
};
49 changes: 10 additions & 39 deletions apps/dashboard/src/@/components/ui/code/plaintext-code.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
"use client";

import { cn } from "@/lib/utils";
import { useClipboard } from "hooks/useClipboard";
import { CheckIcon, CopyIcon } from "lucide-react";
import { ScrollShadow } from "../ScrollShadow/ScrollShadow";
import { Button } from "../button";
import { CodeBlockContainer } from "./CodeBlockContainer";

export function PlainTextCodeBlock(props: {
code: string;
Expand All @@ -13,40 +8,16 @@ export function PlainTextCodeBlock(props: {
scrollableClassName?: string;
codeClassName?: string;
}) {
const { hasCopied, onCopy } = useClipboard(props.code);

return (
<div
className={cn(
"group relative max-w-full overflow-hidden rounded-lg border border-border bg-background",
props.className,
)}
<CodeBlockContainer
codeToCopy={props.code}
className={props.className}
copyButtonClassName={props.copyButtonClassName}
scrollableClassName={props.scrollableClassName}
>
<ScrollShadow
scrollableClassName={cn("p-4", props.scrollableClassName)}
className="text-xs md:text-sm [&_*]:leading-relaxed"
shadowColor="hsl(var(--muted))"
>
<code className={cn("block whitespace-pre", props.codeClassName)}>
{props.code}
</code>
</ScrollShadow>

<Button
size="sm"
variant="outline"
onClick={onCopy}
className={cn(
"absolute top-3.5 right-3.5 h-auto bg-background p-2",
props.copyButtonClassName,
)}
>
{hasCopied ? (
<CheckIcon className="size-3 text-green-500" />
) : (
<CopyIcon className="size-3 text-muted-foreground" />
)}
</Button>
</div>
<code className={cn("block whitespace-pre", props.codeClassName)}>
{props.code}
</code>
</CodeBlockContainer>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -529,11 +529,7 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({

<Card className="flex w-full flex-col gap-2 md:w-1/2">
<Heading size="title.sm">Embed Code</Heading>
<CodeClient
code={embedCode}
lang="html"
loadingClassName="min-h-[190px]"
/>
<CodeClient code={embedCode} lang="html" />
<Button
className="w-auto gap-2"
variant="outline"
Expand Down
1 change: 0 additions & 1 deletion apps/dashboard/src/components/connect/CodePlayground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ const CodePlayground = ({

<QueryClientProvider client={queryClient}>
<CodeClient
loadingClassName="min-h-[490px]"
code={code}
lang={
environment === "react" || environment === "react-native"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ export const MarkdownRenderer: React.FC<{
if (props?.className) {
if (disableCodeHighlight) {
return (
<PlainTextCodeBlock
{...cleanedProps(props)}
code={onlyText(props.children).trim()}
/>
<div className="mb-4">
<PlainTextCodeBlock
{...cleanedProps(props)}
code={onlyText(props.children).trim()}
/>
</div>
);
}
const language = props.className.replace("language-", "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@ export const SourcesAccordion: React.FC<SourcesAccordionProps> = ({
</AccordionButton>
<AccordionPanel>
{isExpanded && (
<CodeClient
code={JSON.stringify(abi, null, 2)}
lang="json"
loadingClassName="min-h-[500px]"
/>
<CodeClient code={JSON.stringify(abi, null, 2)} lang="json" />
)}
</AccordionPanel>
</>
Expand All @@ -67,11 +63,7 @@ export const SourcesAccordion: React.FC<SourcesAccordionProps> = ({
</AccordionButton>
<AccordionPanel>
{isExpanded && (
<CodeClient
code={signature.source.trim()}
lang="solidity"
loadingClassName="min-h-[500px]"
/>
<CodeClient code={signature.source.trim()} lang="solidity" />
)}
</AccordionPanel>
</>
Expand Down
Loading