toddlevy/tl-agent-skills

tl-docs-viewer-create

Create a React admin UI for browsing documentation folders with tree navigation, markdown rendering, Mermaid diagrams, and TOC generation.

Ver código-fonte
Documento original do Skill

Renderizado do repositório de origem, preservando títulos, exemplos, código, tabelas, links e imagens.

<!-- Copyright (c) 2026 Todd Levy. Licensed under MIT. SPDX-License-Identifier: MIT -->

Documentation Viewer UI

Create a browseable documentation viewer for admin interfaces with tree navigation, markdown rendering, and Mermaid diagram support.

When to Use

  • "create docs viewer"
  • "add documentation browser"
  • "admin docs UI"
  • "browse docs folder"
  • "docs viewer component"
  • Adding a docs/ browser to an existing admin area
  • Need to view markdown documentation in-app

Outcomes

  • Artifact: React page component with three-column layout (tree + content + TOC)
  • Artifact: Server API endpoints for tree and content
  • Artifact: Supporting components (DocTree, MermaidMarkdown, OnThisPageNav)
  • Decision: Route placement and library choices

Configuration Discovery

Before implementation, gather project context through structured questions. See references/configuration.md for full schemas.

Question Flow

mermaid
flowchart TD
    Start[Trigger skill] --> Scan[Scan for admin patterns]
    Scan --> Q1[Ask: Admin Area]
    Q1 --> Q2[Ask: Frontend Stack]
    Q2 --> Q3[Ask: Route Placement]
    Q3 --> Q4[Ask: Layout Pattern]
    Q4 --> Q5[Ask: Library Preferences]
    Q5 --> Implement[Implement viewer]

Questions Summary

  1. Admin Area Detection — Existing admin area? (yes/no/scan)
  2. Frontend Stack — React Router / Wouter / Next.js / TanStack Router / Remix
  3. Route Placement — Detected path / /admin/docs / /docs / custom
  4. Layout Pattern — Three-column / Two-column / Single column
  5. Library Preferences — Markdown renderer + data fetching choices

Architecture

Three-Column Layout (Default)

┌─────────────────────────────────────────────────────────────┐
│                    Admin Docs Layout                        │
├──────────┬───────────────────────────────────┬──────────────┤
│          │                                   │              │
│  DocTree │         DocContent                │ OnThisPage   │
│  (250px) │         (flex-1)                  │ (200px)      │
│          │                                   │              │
│  ├─ docs │  # Document Title                 │ - Section 1  │
│  │  ├─ a │                                   │ - Section 2  │
│  │  └─ b │  Content rendered from markdown   │   - Sub 2.1  │
│  └─ ...  │                                   │ - Section 3  │
│          │                                   │              │
└──────────┴───────────────────────────────────┴──────────────┘

Data Flow

mermaid
flowchart TD
    subgraph client [Client]
        Page[DocsViewerPage] --> Tree[DocTree]
        Page --> Content[DocContent]
        Page --> TOC[OnThisPageNav]
        Tree -->|select| Router[Router]
        Router -->|path change| Content
    end
    
    subgraph server [Server]
        TreeAPI["GET /admin/docs/tree"]
        ContentAPI["GET /admin/docs/content/*"]
    end
    
    Tree -->|fetch| TreeAPI
    Content -->|fetch| ContentAPI

Phase 1: Server API

Create two endpoints. See references/server-api.md for full patterns.

GET /admin/docs/tree

Returns folder structure as JSON tree.

typescript
interface DocNode {
  name: string;
  path: string;
  type: 'file' | 'folder';
  children?: DocNode[];
}

GET /admin/docs/content/:path*

Returns markdown content and metadata.

typescript
interface DocContent {
  content: string;
  title: string;
  lastUpdated?: string;
  path: string;
}

Phase 2: React Components

Create the component hierarchy. See references/react-components.md for full architecture.

Components

ComponentPurpose
AdminDocsLayoutThree-column layout wrapper
DocTreeRecursive tree navigation
DocTreeItemSingle tree node with expand/collapse
MermaidMarkdownMarkdown renderer with Mermaid support
OnThisPageNavTOC generated from headings

Phase 3: Integration

Route Setup

Based on detected frontend stack:

StackRoute Pattern
React Router<Route path="/admin/docs/*" element={<DocsViewer />} />
Wouter<Route path="/admin/docs/:path*" component={DocsViewer} />
Next.jsapp/admin/docs/[[...path]]/page.tsx
TanStack RoutercreateRoute({ path: '/admin/docs/$path', component: DocsViewer })

Data Fetching

Based on library preference:

LibraryPattern
TanStack QueryuseQuery({ queryKey: ['docs', 'tree'], queryFn: fetchTree })
SWRuseSWR('/admin/docs/tree', fetcher)
Native fetchuseEffect + useState pattern

Dependencies

Configurable via AskQuestion:

CategoryDefaultAlternatives
Markdown@uiw/react-markdown-previewreact-markdown, marked
Data fetching@tanstack/react-queryswr, native fetch
DiagramsmermaidOptional

Verification

After implementation, verify:

  • [ ] Tree loads and displays folder structure
  • [ ] Clicking file loads markdown content
  • [ ] Mermaid diagrams render (if enabled)
  • [ ] TOC generates from headings
  • [ ] Route navigation works
  • [ ] Dark mode supported (if applicable)

References

FilePurpose
references/configuration.mdAskQuestion flows and branching
references/server-api.mdAPI endpoint patterns
references/react-components.mdComponent architecture
references/templates/Code templates


Markdown Rendering

Streamdown (Recommended)

Streaming-optimized React Markdown renderer with built-in Shiki and Mermaid support.

tsx
import { Streamdown } from 'streamdown';
import { code } from '@streamdown/code';
import { mermaid } from '@streamdown/mermaid';

<Streamdown 
  mode="static" 
  plugins={{ code, mermaid }}
  shikiTheme={['github-light', 'github-dark']}
>
  {content}
</Streamdown>

Tailwind v4 Setup — Add to globals.css:

css
@source "../node_modules/streamdown/dist/*.js";
@source "../node_modules/@streamdown/code/dist/*.js";
@source "../node_modules/@streamdown/mermaid/dist/*.js";

Key Props:

PropTypePurpose
mode`"streaming" \"static"`Use static for docs
plugins{ code?, mermaid?, math? }Feature plugins
shikiTheme[light, dark]Code block themes
controlsbooleanCopy buttons

Alternative: react-markdown

If not using Streamdown:

tsx
import ReactMarkdown from 'react-markdown';
import rehypeHighlight from 'rehype-highlight';
import remarkGfm from 'remark-gfm';

<ReactMarkdown
  remarkPlugins={[remarkGfm]}
  rehypePlugins={[rehypeHighlight]}
>
  {content}
</ReactMarkdown>

Search Integration

Pagefind (Static Search)

Best for pre-built docs. Index at build time, search client-side.

tsx
import { search } from '@pagefind/default-ui';

const results = await search(query);

Flexsearch (Client-Side)

Best for dynamic docs loaded at runtime.

tsx
import FlexSearch from 'flexsearch';

const index = new FlexSearch.Index();
docs.forEach((doc, id) => index.add(id, doc.content));
const results = index.search(query);

Search Modal Pattern

tsx
function SearchModal({ isOpen, onClose }) {
  const [query, setQuery] = useState('');
  const results = useSearch(query);

  return (
    <dialog open={isOpen} onClose={onClose}>
      <input 
        value={query} 
        onChange={e => setQuery(e.target.value)}
        placeholder="Search docs..."
        autoFocus
      />
      <ul role="listbox">
        {results.map(r => (
          <li key={r.path} role="option">
            <a href={r.path}>{r.title}</a>
          </li>
        ))}
      </ul>
    </dialog>
  );
}

Keyboard Navigation

Required Shortcuts

KeyAction
/ or Cmd+KOpen search
EscClose search/modal
Navigate results
EnterSelect result
j kNavigate tree (optional)

Implementation

tsx
useEffect(() => {
  const handler = (e: KeyboardEvent) => {
    if (e.key === '/' && !isInputFocused()) {
      e.preventDefault();
      openSearch();
    }
    if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
      e.preventDefault();
      openSearch();
    }
  };
  document.addEventListener('keydown', handler);
  return () => document.removeEventListener('keydown', handler);
}, []);

Accessibility

ARIA Requirements

tsx
<nav aria-label="Documentation navigation">
  <ul role="tree" aria-label="Docs tree">
    <li role="treeitem" aria-expanded={isOpen} aria-selected={isSelected}>
      <button onClick={toggle}>{name}</button>
    </li>
  </ul>
</nav>

<main role="main" aria-label="Documentation content">
  <article>{content}</article>
</main>

<nav aria-label="On this page">
  <ul>{headings.map(h => <li key={h.id}><a href={`#${h.id}`}>{h.text}</a></li>)}</ul>
</nav>

Focus Management

tsx
function DocTree({ items }) {
  const [focusedIndex, setFocusedIndex] = useState(0);
  
  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key === 'ArrowDown') setFocusedIndex(i => Math.min(i + 1, items.length - 1));
    if (e.key === 'ArrowUp') setFocusedIndex(i => Math.max(i - 1, 0));
    if (e.key === 'Enter') selectItem(items[focusedIndex]);
  };

  return (
    <ul role="tree" onKeyDown={handleKeyDown}>
      {items.map((item, i) => (
        <li 
          key={item.path} 
          role="treeitem"
          tabIndex={i === focusedIndex ? 0 : -1}
          ref={i === focusedIndex ? focusedRef : null}
        >
          {item.name}
        </li>
      ))}
    </ul>
  );
}

MDX Support

For interactive documentation with embedded components:

tsx
import { compile, run } from '@mdx-js/mdx';
import * as runtime from 'react/jsx-runtime';

async function renderMDX(source: string, components: Record<string, Component>) {
  const compiled = await compile(source, { outputFormat: 'function-body' });
  const { default: Content } = await run(compiled, runtime);
  return <Content components={components} />;
}

Custom Components:

tsx
const components = {
  CodePlayground: ({ code }) => <LiveEditor code={code} />,
  Callout: ({ type, children }) => <aside className={`callout-${type}`}>{children}</aside>,
  Steps: ({ children }) => <ol className="steps">{children}</ol>,
};

Documentation Writing Guidelines

From remotion-dev patterns:

  • One API per page — Each function/component gets its own page
  • Don't assume it's easy — Avoid "simply" and "just"
  • Address as "you" — Not "we"
  • Keep it brief — Extra words cause information loss
  • Use headings for fields — Not bullet points for API options
  • Add titles to code fences — Always include file context

Related Skills


References

Quilted Skills

First-Party Documentation

Accessibility

do mesmo repositório

Mais Skills

Todos os Skills
toddlevy
Comunidade

tl-agent-plan-execute

Execute a verified plan document. Consumes verification receipts from tl-agent-plan-audit to avoid redundant re-verification. Defines the trust model, staleness protocol, and exit gate execution process. Use when executing a .plan.md file, starting plan implementation, or when the user says "implement the plan" or "execute the plan".

instalações
1
GitHub Stars
0
Atualizado
8 de set.
toddlevy
Comunidade

tl-kysely-patterns

- Type-safe SQL query building with Kysely for PostgreSQL. Covers query patterns, ExpressionBuilder, JSONB/arrays, migrations, and common pitfalls. Use when writing Kysely queries, creating migrations, debugging type issues, or working with a Kysely codebase.

instalações
1
GitHub Stars
0
Atualizado
8 de set.
toddlevy
Comunidade

tl-live-music-data

Reference documentation for live music data APIs and ID mapping between services. Use when integrating MusicBrainz, Setlist.fm, JamBase, Bandsintown, Ticketmaster, or other concert/artist APIs.

instalações
1
GitHub Stars
0
Atualizado
8 de set.
toddlevy
Comunidade

tl-schema-org

The full Schema.org vocabulary -- all 800+ types, 1500+ properties -- with production patterns for JSON-LD rendering, database modeling, API interoperability, extension governance, and rich results. Not just SEO markup. Use when working with structured data, Schema.org types, JSON-LD, or designing data models and APIs grounded in Schema.org.

instalações
1
GitHub Stars
0
Atualizado
8 de set.