nyxcore-systems
6 min read

Unlocking Project Intelligence: Building a Dynamic Docs Tab with Math, Mermaid & GitHub Sync

We just wrapped up a significant sprint, integrating dynamic documentation directly into our projects dashboard. This post dives into how we built a rich markdown experience, complete with math rendering, Mermaid diagrams, smart link rewriting, and seamless GitHub integration – all while tackling some interesting technical challenges.

documentationmarkdownmermaidkatextrpcgithubfrontendbackenddevelopmentlessons-learnedAI

Documentation is the lifeblood of any complex project, but often it lives in silos, becoming stale or difficult to navigate. Our recent sprint was all about changing that, bringing our project intelligence front and center with a brand-new, dynamic "Docs" tab. The goal? To embed rich, interactive documentation directly within our project dashboards, supporting advanced features like mathematical equations, intricate diagrams, and keeping everything perfectly in sync with our GitHub repositories.

This wasn't just about adding a new UI element; it was a full-stack endeavor involving backend integrations, frontend rendering magic, and a significant content migration.

The Vision: Dynamic, Interactive Documentation

Imagine a project dashboard where, alongside your code, issues, and analytics, you have a dedicated space for deep dives into its architecture, pipelines, and core concepts. This space wouldn't just display static text; it would render complex flowcharts, sequence diagrams, and mathematical formulas precisely as they're written in markdown. And critically, these docs would live alongside the code in GitHub, ensuring they're always versioned and up-to-date.

Our sprint focused on three core objectives:

  1. A Dedicated Docs Tab: A new section within each project's dashboard to list and display documentation.
  2. Advanced Markdown Support: Integrating mermaid for diagrams and katex for mathematical notation ($inline$ and $$block$$).
  3. Content Migration: Moving 20 critical intelligence documents from temporary files into a structured docs/ folder within our main repository.

I'm thrilled to report: all objectives are complete!

Backend Power-Up: GitHub as Our Documentation Source

The first step was to treat our GitHub repositories as the single source of truth for documentation. This meant building a robust backend integration capable of fetching and parsing files directly from a linked repo.

In src/server/trpc/routers/projects.ts, we extended our projects router with a new docs sub-router:

typescript
// src/server/trpc/routers/projects.ts
import { fetchRepoTree, fetchFileContent } from 'github-connector'; // Simplified for example

// ... inside projectRouter.createCaller()
docs: t.router({
  list: t.procedure
    .input(z.object({ projectId: z.string() }))
    .query(async ({ input }) => {
      // Logic to get owner/repo from projectId
      const repoTree = await fetchRepoTree(owner, repo, 'main');
      return repoTree
        .filter(item => item.path.startsWith('docs/') && item.path.endsWith('.md'))
        .map(item => ({
          path: item.path,
          name: item.path.replace('docs/', '').replace('.md', '')
        }));
    }),

  get: t.procedure
    .input(z.object({ projectId: z.string(), filePath: z.string() }))
    .query(async ({ input }) => {
      // Logic to get owner/repo from projectId
      const content = await fetchFileContent(owner, repo, input.filePath, 'main');
      // Extract title from first H1, summary from first paragraph
      const titleMatch = content.match(/^#\s(.+?)(?:\n|$)/);
      const summaryMatch = content.match(/^[\s\S]*?#\s.*?[\s\S]*?(?:\n\n|\n#|$)/); // Improved regex
      return {
        content,
        title: titleMatch ? titleMatch[1] : 'Untitled',
        summary: summaryMatch ? summaryMatch[0].trim() : ''
      };
    }),
}),

This setup allows us to:

  • docs.list({ projectId }): Fetch the entire repository tree, filter for markdown files in the docs/ directory, and present them as a list of names and paths.
  • docs.get({ projectId, filePath }): Retrieve the raw content of a specific markdown file, intelligently extracting its title and a brief summary for quick previews.

Frontend Magic: Elevating the Markdown Renderer

The real heavy lifting on the frontend happened within our src/components/markdown-renderer.tsx. This component is now a powerhouse, capable of handling complex markdown syntax.

Math Rendering with KaTeX

For our more technical documentation, inline ($E=mc^2$) and block ($$\sum_{i=1}^n i = \frac{n(n+1)}{2}$$) mathematical equations are crucial. We integrated remark-math and rehype-katex into our markdown processing pipeline:

typescript
// src/components/markdown-renderer.tsx
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import 'katex/dist/katex.min.css'; // For KaTeX styling

// ... inside MarkdownRenderer component
<ReactMarkdown
  remarkPlugins={[remarkGfm, remarkMath]}
  rehypePlugins={[rehypeRaw, rehypeSlug, rehypeKatex]}
  // ...
>
  {markdownContent}
</ReactMarkdown>

This transformation pipeline ensures that any LaTeX-style math syntax is correctly parsed and rendered into beautiful, accessible mathematical expressions.

Dynamic Diagrams with Mermaid

Visual aids, especially diagrams, can convey complex information far more effectively than text alone. We wanted to support Mermaid, allowing developers to embed flowcharts, sequence diagrams, and more directly in markdown code blocks.

This involved a new MermaidDiagram component, dynamically imported for performance, and a custom CodeBlockWrapper to detect and delegate language-mermaid blocks:

typescript
// src/components/mermaid-diagram.tsx (simplified)
import dynamic from 'next/dynamic';
const Mermaid = dynamic(() => import('mermaid').then(m => m.default), { ssr: false });

interface MermaidDiagramProps {
  chart: string;
}

const MermaidDiagram: React.FC<MermaidDiagramProps> = ({ chart }) => {
  const chartRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (chartRef.current) {
      Mermaid.initialize({ theme: 'dark' }); // Ensure dark theme
      Mermaid.render('mermaid-chart', chart).then(({ svg }) => {
        if (chartRef.current) {
          chartRef.current.innerHTML = svg;
        }
      });
    }
  }, [chart]);

  return <div ref={chartRef} className="mermaid-container" />;
};

// src/components/markdown-renderer.tsx (excerpt)
const CodeBlockWrapper: React.FC<CodeProps> = ({ inline, className, children, ...props }) => {
  const match = /language-(\w+)/.exec(className || '');
  if (match?.[1] === 'mermaid') {
    return <MermaidDiagram chart={String(children).trim()} />;
  }
  // ... existing code block rendering
};

// ... in ReactMarkdown components prop
components={{
  code: CodeBlockWrapper,
}}

This setup ensures Mermaid diagrams are rendered as SVG, respecting our dark theme, and only loaded when needed.

Smart Link Rewriting with RepoLink

A subtle but powerful improvement was the RepoLink component. When documentation contains internal links (e.g., [My Component](/src/components/MyComponent.tsx)), these links would break when viewed in our app, or worse, point to a non-existent local path. Our RepoLink component intelligently rewrites these internal paths to their corresponding GitHub blob URLs, ensuring seamless navigation to the source code directly from the documentation.

typescript
// src/components/markdown-renderer.tsx (simplified)
interface RepoLinkProps extends HTMLProps<HTMLAnchorElement> {
  href?: string;
  githubOwner?: string;
  githubRepo?: string;
}

const RepoLink: React.FC<RepoLinkProps> = ({ href, githubOwner, githubRepo, children, ...props }) => {
  const internalPathRegex = /^(src|lib|app|pages|components|server|prisma|tests|docs|scripts|public)\//;
  if (href && internalPathRegex.test(href) && githubOwner && githubRepo) {
    const githubBlobUrl = `https://github.com/${githubOwner}/${githubRepo}/blob/main/${href}`;
    return <a href={githubBlobUrl} target="_blank" rel="noopener noreferrer" {...props}>{children}</a>;
  }
  return <a href={href} {...props}>{children}</a>;
};

// ... in ReactMarkdown components prop
components={{
  a: ({ node, ...props }) => <RepoLink {...props} githubOwner={githubOwner} githubRepo={githubRepo} />,
}}

We also used useMemo for the components object passed to ReactMarkdown to prevent unnecessary re-renders, a small but important performance detail.

The User Experience: A Dedicated Docs Tab

Finally, bringing all this together into a cohesive user experience meant integrating a new DocsTab component into our project dashboard.

In src/app/(dashboard)/dashboard/projects/[id]/page.tsx, we added a new TabsTrigger and TabsContent for "Docs," positioned logically after "Actions."

The DocsTab itself is a stateful component with three views:

  1. List Grid: Displays all available documentation files as cards, fetched via trpc.projects.docs.list.
  2. Summary Card: When a doc is selected, a summary (extracted from the first paragraph) is shown along with its title.
  3. Full Doc View: The complete markdown content, rendered by our enhanced MarkdownRenderer, fetched via trpc.projects.docs.get.

This progressive disclosure ensures a clean, responsive interface, allowing users to quickly browse, preview, and then dive deep into the documentation they need.

Structuring Knowledge: Our 20-Section Intelligence Core

Beyond the technical implementation, a significant part of this sprint involved migrating and structuring 20 core intelligence documents. These documents detail everything from our "Auto-Fix Pipeline" (a 4-phase system with NerdStats integration) and "Refactor Pipeline" (categorizing difficulty tiers and patch restrictions) to "Code Analysis" (covering file indexing, pattern types, and quality scoring), "Action Points," "Discussion Service," and deep dives into our "GitHub Connector" and "Analytics Dashboard."

Each document now resides as an individual markdown file within the docs/ directory, ensuring modularity and easy management.

Lessons Learned from the