Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 5 additions & 1 deletion cloud/app/components/docs-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ function createSidebarConfig(): SidebarConfig {

allDocInfo.forEach((doc) => {
// Extract the slug pattern from the path
const keyPath = doc.path;
// Strip "docs/" prefix to match the lookup format
const prefix = "docs/";
const keyPath = doc.path.startsWith(prefix)
? doc.path.slice(prefix.length)
: doc.path;
slugToRoutePathMap.set(keyPath, doc.routePath);
});

Expand Down
182 changes: 91 additions & 91 deletions cloud/app/components/mdx/component-registry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { Button } from "@/app/components/ui/button";
import { ButtonLink } from "@/app/components/ui/button-link";
import MirascopeLogo from "@/app/components/blocks/branding/mirascope-logo";
import ProductLogo from "@/app/components/blocks/branding/mirascope-logo";
// import { ProviderCodeWrapper } from "./ProviderCodeWrapper";
import { ModelProviderCodeWrapper } from "@/app/components/mdx/elements/model-provider-code-wrapper";
// import { ResponsiveImage } from "@/src/components/mdx/providers/ResponsiveImage";
// import { devComponents } from "@/app/components/mdx/elements/DevComponents";
import { idSlugFromChildren } from "@/app/lib/mdx/heading-utils";
Expand Down Expand Up @@ -338,95 +338,95 @@ const mediaElements = {
},
};

// todo(sebastian): bring back code elements
// const codeElements = {
// // Inline code - this is only for inline elements, not code blocks
// code: (props: React.ComponentPropsWithoutRef<"code">) => {
// // Don't apply inline code styling to code blocks (which are children of pre tags)
// const isInPre = React.useRef<boolean>(false);
// React.useLayoutEffect(() => {
// // Type assertion for DOM properties access
// const element = props as unknown as {
// parentElement?: { tagName: string };
// };
// const parentIsPre =
// props.className?.includes("language-") ||
// props.className?.includes("shiki") ||
// element.parentElement?.tagName === "PRE";
// isInPre.current = !!parentIsPre;
// }, [props]);

// // Only apply inline code styling to actual inline code, not code blocks
// if (isInPre.current) {
// return <code {...props} />;
// }

// return (
// <code
// className="bg-muted text-muted-foreground rounded px-1 py-0.5 font-mono text-[0.9em]"
// {...props}
// />
// );
// },

// // Code blocks - use our custom CodeBlock component with provider substitution
// pre: (props: React.ComponentPropsWithoutRef<"pre">) => {
// // Get meta information from our data attribute or initialize to empty
// let meta = (props as any)["data-meta"] || "";

// // Initialize variables for code content and language
// let codeContent = "";
// let language = "txt";

// // Process children to find code content and language
// if (props.children) {
// const children = React.Children.toArray(props.children);

// // Loop through children to find code content (typically there's only one child)
// for (const child of children) {
// if (!React.isValidElement(child)) continue;

// // Check if this is a code element or has code-like properties
// const childProps = child.props as {
// className?: string;
// children?: React.ReactNode | string;
// };

// // Extract language from className
// if (childProps.className?.includes("language-")) {
// language =
// (childProps.className.match(/language-(\w+)/) || [])[1] || "txt";

// // Also check for meta in className (legacy approach)
// // This looks for patterns like {1-3} or {1,3} after the language
// if (!meta) {
// const metaMatch = childProps.className.match(/\{([^}]+)\}/);
// meta = metaMatch ? `{${metaMatch[1]}}` : "";
// }
// }

// // Get code content
// if (typeof childProps.children === "string") {
// codeContent = childProps.children;
// break;
// }
// }
// }

// // Handle mermaid diagrams
// if (language === "mermaid" && codeContent) {
// return <MermaidDiagram chart={codeContent.trim()} />;
// }

// return (
// <ProviderCodeWrapper
// code={codeContent.replace(/\n$/, "")}
// language={language}
// meta={meta}
// />
// );
// },
// };
const codeElements = {
// Inline code - this is only for inline elements, not code blocks
code: (props: React.ComponentPropsWithoutRef<"code">) => {
// Don't apply inline code styling to code blocks (which are children of pre tags)
const isInPre = React.useRef<boolean>(false);
React.useLayoutEffect(() => {
// Type assertion for DOM properties access
const element = props as unknown as {
parentElement?: { tagName: string };
};
const parentIsPre =
props.className?.includes("language-") ||
props.className?.includes("shiki") ||
element.parentElement?.tagName === "PRE";
isInPre.current = !!parentIsPre;
}, [props]);

// Only apply inline code styling to actual inline code, not code blocks
if (isInPre.current) {
return <code {...props} />;
}

return (
<code
className="bg-muted text-muted-foreground rounded px-1 py-0.5 font-mono text-[0.9em]"
{...props}
/>
);
},

// Code blocks - use our custom CodeBlock component with provider substitution
pre: (props: React.ComponentPropsWithoutRef<"pre">) => {
// Get meta information from our data attribute or initialize to empty
let meta =
(props as unknown as { "data-meta"?: string })["data-meta"] || "";

// Initialize variables for code content and language
let codeContent = "";
let language = "txt";

// Process children to find code content and language
if (props.children) {
const children = React.Children.toArray(props.children);

// Loop through children to find code content (typically there's only one child)
for (const child of children) {
if (!React.isValidElement(child)) continue;

// Check if this is a code element or has code-like properties
const childProps = child.props as {
className?: string;
children?: React.ReactNode | string;
};

// Extract language from className
if (childProps.className?.includes("language-")) {
language =
(childProps.className.match(/language-(\w+)/) || [])[1] || "txt";

// Also check for meta in className (legacy approach)
// This looks for patterns like {1-3} or {1,3} after the language
if (!meta) {
const metaMatch = childProps.className.match(/\{([^}]+)\}/);
meta = metaMatch ? `{${metaMatch[1]}}` : "";
}
}

// Get code content
if (typeof childProps.children === "string") {
codeContent = childProps.children;
break;
}
}
}

// Handle mermaid diagrams
if (language === "mermaid" && codeContent) {
return <MermaidDiagram chart={codeContent.trim()} />;
}

return (
<ModelProviderCodeWrapper
code={codeContent.replace(/\n$/, "")}
language={language}
meta={meta}
/>
);
},
};

// -----------------------------------------------------------------------------
// Complete Component Registry
Expand All @@ -439,5 +439,5 @@ export default {
...listElements,
...tableElements,
...mediaElements,
// ...codeElements,
...codeElements,
};
63 changes: 63 additions & 0 deletions cloud/app/components/mdx/elements/analytics-code-block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useRef, useMemo } from "react";
import { CodeBlock } from "@/app/components/blocks/code-block/code-block";
// import analyticsManager from "@/src/lib/services/analytics";

interface AnalyticsCodeBlockProps {
code: string;
language?: string;
meta?: string;
className?: string;
showLineNumbers?: boolean;
}

export function AnalyticsCodeBlock({
code,
language,
meta,
className,
showLineNumbers,
}: AnalyticsCodeBlockProps) {
const codeRef = useRef<HTMLDivElement>(null);

// Create a stable identifier for this code block based on its content
// This ensures the ID remains consistent across rerenders
const codeHash = useMemo(() => {
// Simple hash function for the code content
let hash = 0;
for (let i = 0; i < code.length; i++) {
const char = code.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32bit integer
}
return Math.abs(hash).toString(16).substring(0, 8);
}, [code]);

const onCopy = () => {
// const pagePath = window.location.pathname;
// Use path, language and hash of code to create a stable identifier
// const itemId = `${pagePath}#${language || "code"}-${codeHash}`;
// analyticsManager.trackCopyEvent({
// contentType: "code_snippet",
// itemId,
// product,
// language: language || "text",
// });
};

return (
<div
ref={codeRef}
data-code-hash={codeHash}
className="analytics-code-block"
>
<CodeBlock
code={code}
language={language}
meta={meta}
className={className}
showLineNumbers={showLineNumbers}
onCopy={onCopy}
/>
</div>
);
}
9 changes: 5 additions & 4 deletions cloud/app/components/mdx/elements/code-block-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import LoadingContent from "@/app/components/blocks/loading-content";
import { useProvider } from "@/app/components/mdx/elements/model-provider-provider";
// import { AnalyticsCodeBlock } from "./AnalyticsCodeBlock";
import { AnalyticsCodeBlock } from "./analytics-code-block";
interface ProviderCodeBlockProps {
examplePath: string; // Path relative to public/examples
language?: string;
Expand All @@ -14,7 +14,7 @@ interface ProviderCodeBlockProps {
*/
export default function ProviderCodeBlock({
examplePath,
// language = "python",
language = "python",
className = "",
}: ProviderCodeBlockProps) {
// Get the currently selected provider
Expand Down Expand Up @@ -81,8 +81,9 @@ export default function ProviderCodeBlock({
Example for {provider} not available yet.
</div>
)}
{/* {currentProviderCode && <AnalyticsCodeBlock code={currentProviderCode} language={language} />} */}
{currentProviderCode && "AnalyticsCodeBlock"}
{currentProviderCode && (
<AnalyticsCodeBlock code={currentProviderCode} language={language} />
)}
</>
);
}
7 changes: 2 additions & 5 deletions cloud/app/components/mdx/elements/install-snippet.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useProvider } from "@/app/components/mdx/elements/model-provider-provider";
import type { Provider } from "@/app/components/mdx/elements/model-provider-provider";
// import { AnalyticsCodeBlock } from "@/app/components/blocks/mdx/AnalyticsCodeBlock";
import { AnalyticsCodeBlock } from "@/app/components/mdx/elements/analytics-code-block";
import { cn } from "@/app/lib/utils";
import { TabbedSection, Tab } from "./tabbed-section";

Expand Down Expand Up @@ -44,8 +44,6 @@ export function InstallSnippet({ className = "" }: InstallSnippetProps) {
const { provider } = useProvider();

// Generate install commands for each OS
// @ts-expect-error until todo(sebastian): add back code elements
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const generateCommand = (os: OS) => {
const setEnvCmd = os === "MacOS / Linux" ? "export" : "set";
const apiKeyVar = providerApiKeys[provider];
Expand All @@ -63,8 +61,7 @@ export function InstallSnippet({ className = "" }: InstallSnippetProps) {
<TabbedSection className={cn(className)}>
{operatingSystems.map((os) => (
<Tab key={os} value={os}>
{/* <AnalyticsCodeBlock code={generateCommand(os)} language="bash" /> */}
AnalyticsCodeBlock
<AnalyticsCodeBlock code={generateCommand(os)} language="bash" />
</Tab>
))}
</TabbedSection>
Expand Down
38 changes: 38 additions & 0 deletions cloud/app/components/mdx/elements/model-provider-code-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// No need to import React with JSX transform
import {
useProvider,
replaceProviderVariables,
} from "@/app/components/mdx/elements/model-provider-provider";
import { AnalyticsCodeBlock } from "@/app/components/mdx/elements/analytics-code-block";

/**
* A wrapper component for code blocks that handles provider-specific substitutions.
* This allows us to use standard markdown code blocks with provider-specific variables.
*/
export function ModelProviderCodeWrapper({
code,
language,
meta,
className,
}: {
code: string;
language: string;
meta?: string;
className?: string;
}) {
const { provider } = useProvider();

// Only process python or bash code
if (code && (language === "python" || language === "bash")) {
code = replaceProviderVariables(code, provider);
}

return (
<AnalyticsCodeBlock
className={className}
code={code}
language={language}
meta={meta}
/>
);
}
1 change: 1 addition & 0 deletions cloud/app/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const buttonVariants = cva(
"[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0",
"outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
"font-handwriting",
].join(" "),
{
variants: {
Expand Down
Loading