Wednesday, February 11, 2026

next.js дээр markdown файлыг уншаад хэрхэн html хуудас болгож харуулах вэ?

 'use client';

import { ChevronDown, FileText } from 'lucide-react';
import React, { useEffect, useState } from 'react';

import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
import rehypeHighlight from 'rehype-highlight';

type TreeNode = {
    title: string;
    docPath: string;
    children?: TreeNode[];
};

const helpNodes: TreeNode[] = [
    {
        title: 'Үндсэн ойлголт',
        docPath: 'index.md',
    },
    {
        title: 'Хэрэглэгчид',
        docPath: 'users.md',
    },
];

function TreeItem({
    par,
    node,
    onLoadDoc,
}: {
    par: string;
    node: TreeNode;
    onLoadDoc: (docPath: string) => void;
}) {
    const hasChildren = node.children && node.children.length > 0;

    const handleItemClick = (e: React.MouseEvent) => {
        e.preventDefault();
        onLoadDoc(node.docPath);
    };

    return (
        <div className="ml-2">
            <div className="flex items-center gap-1">
                {hasChildren ? (
                    <ChevronDown size={16} />
                ) : (
                    <FileText size={16} />
                )}
                <a href="#" onClick={handleItemClick}>
                    <span>{node.title}</span>
                </a>
            </div>
            {hasChildren && (
                <div className="ml-4 mt-1 space-y-1">
                    {node.children!.map((child, index) => (
                        <TreeItem
                            key={par + '-' + index}
                            par={par + '-' + index}
                            node={child}
                            onLoadDoc={onLoadDoc}
                        />
                    ))}
                </div>
            )}
        </div>
    );
}

export default function HelpPage() {
    const [doc, setDoc] = useState('');

    const handleLoadDoc = async (docPath: string) => {
        try {
            const queryParams = new URLSearchParams();
            queryParams.append('md', `${docPath}`);
            fetch(`/api/md-docs/help?${queryParams.toString()}`)
                .then((res) => res.text())
                .then(async (data) => {
                    setDoc(data);
                });
        } catch (error) {
            console.error('Error loading document:', error);
        }
    };

    useEffect(() => {
        handleLoadDoc(helpNodes[0].docPath);
    }, []);

    return (
        <div className="flex-row-container gap-4">
            <div className="y-scroll-transparent w-64 bg-gray-100 border-r border-gray-200">
                <h1 className="text-xl font-semibold my-4 mx-2">Тусламж</h1>
                {helpNodes.map((node, index) => {
                    return (
                        <TreeItem
                            key={'TreeItem-' + index}
                            par={'TreeItem-' + index}
                            node={node}
                            onLoadDoc={handleLoadDoc}
                        />
                    );
                })}
                <div className="h-screen display-none">hello</div>
            </div>
            <div className="flex-scrollable-panel">
                <article
                    id="md-docs"
                    className="prose prose-slate max-w-none
                        prose-headings:font-bold
                        prose-a:text-blue-600
                        prose-pre:bg-gray-900
                        prose-pre:text-gray-100"
                >
                    <ReactMarkdown
                        rehypePlugins={[
                            rehypeRaw,
                            [rehypeHighlight, { ignoreMissing: true }],
                        ]}
                    >
                        {doc}
                    </ReactMarkdown>
                </article>
            </div>
        </div>
    );
}

No comments: