Friday, March 20, 2026

tailwind grid grid-flow-col grid-rows-5, grid grid-flow-row grid-cols-5, h-screen overflow-auto strategy

return <div className="relative h-screen">

            {/* <AnalyticsWidget /> */}

            <div className="grid grid-flow-col grid-rows-5 h-screen display-none">

                <div className="row-span-2 border-b border-b-gray-300">

                    aaaaaaa

                </div>

                <div className="row-span-3 border-b border-b-gray-300">

                    bbbbbbb

                </div>

                <div className="row-span-5 border-l border-r border-l-gray-300 border-r-gray-500">

                    ccccccc

                </div>

            </div>

            <div className="grid grid-flow-row grid-cols-5 h-screen overflow-auto">

                <div className="col-span-2 border-b border-b-gray-300">

                    aaaaaaa

                </div>

                <div className="col-span-3 border-b border-b-gray-300">

                    bbbbbbb

                </div>

                <div className="col-span-5 border-l border-r border-l-gray-300 border-r-gray-500">

                    ccccccc

                    <div className='h-296'>dddddddd</div>

                </div>

            </div>

        </div> 

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>
    );
}

Tuesday, February 10, 2026

how to response markdown file using next.js , nest.js

 on nest.js

import {
    Body,
    Controller,
    Get,
    HttpStatus,
    Post,
    Render,
    Req,
    Res,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { Throttle } from '@nestjs/throttler';
import * as fs from 'fs';
import * as path from 'path';

import { AppSessionService } from '../core/app.session.service';
import { AppConstants } from '../core/app.constants';
import { DataMemoryCacher } from '../libs/memory-cacher/data.memory-cacher';

@Controller()
export class AppController {
    constructor(
        private readonly dataCacher: DataMemoryCacher,
        private readonly appSessionService: AppSessionService,
    ) {}

    @Get('/')
    @Render('home')
    app_home(@Req() req: Request, @Res() res: Response): any {
        var hosts = [req.headers.host];
        var username = this.appSessionService.getUserName();
        let last_one = this.dataCacher.get('puu_last_one_from');

        return {
            title: 'PUU - PAAS',
            hosts: hosts,
            username: username,
            last_one: last_one ? last_one.doc_num : '-0-',
        };
    }

    @Get('/about')
    async app_about(@Req() req: Request, @Res() res: Response): Promise<any> {
        let apiDoc = '';

        // // load from cache
        // const keyCache = 'site-home-md';
        // // const dataCache = this.dataCacher.get(keyCache);
        // const dataCache = null;

        // if (dataCache) {
        //     apiDoc = dataCache;
        // } else {
        //     const mdPath = path.join(process.cwd(), 'views', 'about-api.md');
        //     apiDoc = fs.readFileSync(mdPath, 'utf8');
        //     this.dataCacher.set(keyCache, apiDoc);
        // }

        res.render('about', {
            title: 'PUU - About API',
            apiDoc,
        });
    }

    @Get('apiDocs.md')
    getApiDoc(@Res() res: Response) {
        const mdPath = path.join(process.cwd(), 'views', 'about-api.md');
        const md = fs.readFileSync(mdPath, 'utf8');
        res.type('text/markdown').send(md);
    }

    // for API

    @Throttle(AppConstants.throttler_limits.website_send)
    @Post('/language')
    app_language_sel(@Body() body: any, @Res() res: Response) {
        if (body.code && AppConstants.supported_languages.includes(body.code)) {
            this.appSessionService.setLanguage(body.code);

            return res
                .status(HttpStatus.OK)
                .json({ success: true, result: body.code });
        }
        return res.status(HttpStatus.BAD_REQUEST).json({ success: false });
    }

    @Throttle(AppConstants.throttler_limits.brute_force)
    @Get('/ip')
    ip(@Req() req: Request, @Res() res: Response) {
        return res.status(HttpStatus.OK).json({
            ip: req.ip,
            forwarded: req.headers['x-forwarded-for'],
        });
    }
}


on next.js


import fs from 'fs';
import path from 'path';
import { NextResponse } from 'next/server';

export async function GET() {
    const mdPath = path.join(process.cwd(), 'docs', 'about-api.md');
    const md = fs.readFileSync(mdPath, 'utf8');

    return new NextResponse(md, {
        headers: {
            'Content-Type': 'text/markdown; charset=utf-8',
        },
    });
}




Tuesday, February 3, 2026

PM2-г Ubuntu дээр бүрэн устгах хэдэн алхам байна

 PM2-г Ubuntu дээр бүрэн устгах хэдэн алхам байна. Энэ нь зөвхөн програмыг устгахгүй, мөн лог файлууд болон тохиргоог устгана, иймээс диск чөлөөлөхөд тохиромжтой.


1️⃣ PM2 процессыг зогсоох

pm2 kill
  • Бүх PM2 процессуудыг зогсооно.


2️⃣ PM2-г uninstall хийх

sudo npm uninstall -g pm2
  • PM2-г глобал түвшинд uninstall хийж байна.


3️⃣ PM2 тохиргоо, лог файлуудыг устгах

rm -rf ~/.pm2
  • ~/.pm2 хавтас дотор:

    • logs/ → бүх stdout/stderr log

    • dump.pm2 → процессын snapshot

    • бусад config файлууд бүгд устна


4️⃣ (Optional) PM2 logrotate module-г устгах

Хэрвээ суулгасан бол:

pm2 uninstall pm2-logrotate

5️⃣ Диск зайг шалгах

df -h
  • /home хавтасны зай чөлөөлөгдсөн эсэхийг харах.


⚠️ Санамж:

  • Энэ аргаар PM2 бүх тохиргоо, лог, процессыг устгана.

  • Хэрвээ ирээдүйд дахин ашиглах гэж байгаа бол зөвхөн лог файлуудыг truncate хийх нь илүү аюулгүй арга.