티스토리 뷰

WEB/JQuery

상세 클릭포함 트리메뉴

silverline79 2026. 1. 22. 13:42

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>관리자용 트리 탐색기 & 상세 보기</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        /* [1] 기본 레이아웃 설정 */
        body { font-family: 'Malgun Gothic', sans-serif; margin: 0; display: flex; height: 100vh; background: #f0f2f5; overflow: hidden; }
        
        /* 왼쪽 사이드바 */
        .sidebar { width: 380px; background: #fff; border-right: 1px solid #dcdfe6; padding: 25px; overflow-y: auto; box-shadow: 2px 0 5px rgba(0,0,0,0.05); }
        
        /* 오른쪽 상세 내용 영역 */
        .content-view { flex: 1; padding: 50px; background: #fff; overflow-y: auto; display: flex; flex-direction: column; }

        /* 컨트롤 및 검색 */
        .control-btns { display: flex; gap: 8px; margin-bottom: 12px; justify-content: flex-end; }
        .btn { padding: 6px 12px; font-size: 12px; cursor: pointer; border: 1px solid #dcdfe6; background: #fff; border-radius: 5px; transition: all 0.2s; }
        .btn:hover { background: #409eff; color: #fff; border-color: #409eff; }
        .search-box input { width: 100%; padding: 12px; margin-bottom: 20px; border: 1px solid #dcdfe6; border-radius: 8px; outline: none; box-sizing: border-box; }
        .search-box input:focus { border-color: #409eff; }

        /* 트리 메뉴 CSS */
        ul.tree, ul.tree ul { list-style: none; padding-left: 20px; margin: 0; }
        .tree li { margin: 5px 0; position: relative; }
        .folder, .file { padding: 8px 12px; cursor: pointer; border-radius: 6px; display: inline-block; font-size: 14px; color: #606266; }
        .folder:hover, .file:hover { background-color: #f5f7fa; color: #409eff; }
        .active-item { background-color: #ecf5ff !important; color: #409eff; font-weight: bold; }

        /* 폴더 상태 제어 */
        .folder + ul { display: block; } 
        .folder.collapsed + ul { display: none; }
        
        /* 하이라이트 */
        .highlight { background-color: #fff3cd !important; border: 1px solid #ffeeba; }
        #no-result { display: none; text-align: center; color: #909399; padding: 20px; }

        /* 상세 페이지 내부 스타일 */
        .detail-header { border-bottom: 2px solid #f0f2f5; padding-bottom: 20px; margin-bottom: 30px; }
        .detail-card { background: #fdfdfd; border: 1px solid #ebeef5; border-radius: 10px; padding: 25px; line-height: 1.8; }
        .info-label { font-weight: bold; color: #909399; width: 100px; display: inline-block; }
        .empty-state { text-align: center; color: #c0c4cc; margin-top: 150px; }
    </style>
</head>
<body>

    <div class="sidebar">
        <h2 style="font-size: 1.2rem; color: #303133;">📂 시스템 탐색기</h2>
        
        <div class="control-btns">
            <button id="btn-expand" class="btn">전체 열기</button>
            <button id="btn-collapse" class="btn">전체 닫기</button>
        </div>

        <div class="search-box">
            <input type="text" id="tree-search" placeholder="파일/폴더 명칭 검색...">
        </div>

        <div id="no-result">검색 결과가 없습니다.</div>
        <ul class="tree" id="main-tree"></ul>
    </div>

    <div class="content-view">
        <div id="view-empty" class="empty-state">
            <p style="font-size: 60px;">🔍</p>
            <p>왼쪽 탐색기에서 항목을 선택해 주세요.</p>
        </div>

        <div id="view-detail" style="display: none;">
            <div class="detail-header">
                <h1 id="det-title" style="margin:0; font-size: 28px; color: #303133;">파일명</h1>
                <span id="det-badge" style="background:#409eff; color:#fff; padding:3px 10px; border-radius:15px; font-size:12px;">파일</span>
            </div>
            
            <div class="detail-card">
                <div><span class="info-label">이름:</span> <span id="info-name">-</span></div>
                <div><span class="info-label">경로:</span> <span id="info-path">-</span></div>
                <div><span class="info-label">유형:</span> <span id="info-type">-</span></div>
                <div><span class="info-label">수정일:</span> 2026-01-22</div>
                <div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #eee;">
                    <p><strong>내용 요약:</strong></p>
                    <p id="info-desc" style="color: #666;">해당 항목의 상세 데이터 정의를 API로부터 불러오는 중입니다...</p>
                </div>
            </div>
        </div>
    </div>

<script>
$(document).ready(function() {
    // 1. 샘플 데이터 (실제 서비스에선 AJAX로 받아옴)
    const jsonData = [
        {
            "name": "경영관리_본부",
            "type": "folder",
            "children": [
                {
                    "name": "인사기획팀",
                    "type": "folder",
                    "children": [
                        { "name": "2026_채용계획.pdf", "type": "file" },
                        { "name": "연봉테이블.xlsx", "type": "file" }
                    ]
                },
                { "name": "전략보고서_최종.pptx", "type": "file" }
            ]
        },
        { "name": "공통_사규_가이드.pdf", "type": "file" }
    ];

    // 2. 트리 생성 함수
    function renderTree(data, path = "") {
        let html = "";
        data.forEach(item => {
            const currentPath = path + " > " + item.name;
            if (item.type === "folder") {
                html += `<li>
                            <div class="folder" data-path="${currentPath}">📂 ${item.name}</div>
                            <ul>${renderTree(item.children, currentPath)}</ul>
                         </li>`;
            } else {
                html += `<li class="file" data-path="${currentPath}">📄 ${item.name}</li>`;
            }
        });
        return html;
    }

    // 트리 초기 렌더링
    $('#main-tree').html(renderTree(jsonData));

    // 3. 폴더 클릭(토글) 기능
    $(document).on('click', '.folder', function(e) {
        if (!$(e.target).hasClass('search-mode')) { // 검색 모드가 아닐 때만 토글
            $(this).toggleClass('collapsed');
            $(this).next('ul').slideToggle(200);
        }
    });

    // 4. 상세 내용 출력 로직 (핵심)
    $(document).on('click', '.folder, .file', function(e) {
        e.stopPropagation();
        
        // 시각적 강조 효과
        $('.folder, .file').removeClass('active-item');
        $(this).addClass('active-item');

        const rawName = $(this).text().replace(/📂|📄/g, '').trim();
        const path = $(this).data('path').substring(3);
        const type = $(this).hasClass('folder') ? '폴더' : '파일';

        // 우측 뷰 전환
        $('#view-empty').hide();
        $('#view-detail').fadeIn(300);

        // 데이터 바인딩
        $('#det-title, #info-name').text(rawName);
        $('#det-badge, #info-type').text(type);
        $('#info-path').text(path);
        
        if(type === '폴더') {
            $('#info-desc').text(`'${rawName}' 폴더 내의 하위 리스트를 관리합니다. 상단 버튼을 통해 폴더 내 파일을 일괄 수정할 수 있습니다.`);
            $('#det-badge').css('background', '#67c23a'); // 폴더는 초록색
        } else {
            $('#info-desc').text(`'${rawName}' 파일의 세부 명세입니다. 이 파일은 시스템 보안 정책에 의해 암호화되어 보호받고 있습니다.`);
            $('#det-badge').css('background', '#409eff'); // 파일은 파란색
        }
    });

    // 5. 전체 제어 버튼
    $('#btn-expand').click(function() {
        $('.folder').removeClass('collapsed').next('ul').slideDown(200);
    });

    $('#btn-collapse').click(function() {
        $('.folder').addClass('collapsed').next('ul').slideUp(200);
    });

    // 6. 검색 기능 (텍스트 기반)
    $('#tree-search').on('input', function() {
        const query = $(this).val().toLowerCase().trim();
        const $allLi = $('#main-tree li');

        $('.folder, .file').removeClass('highlight');

        if (!query) {
            $allLi.show();
            $('#no-result').hide();
            return;
        }

        $allLi.hide();
        let found = false;

        $allLi.each(function() {
            const text = $(this).text().toLowerCase();
            if (text.indexOf(query) !== -1) {
                $(this).show().parents('li').show();
                $(this).parents('ul').show().prev('.folder').removeClass('collapsed');
                
                $(this).children('.folder, .file').each(function() {
                    if($(this).text().toLowerCase().indexOf(query) !== -1) {
                        $(this).addClass('highlight');
                    }
                });
                found = true;
            }
        });
        found ? $('#no-result').hide() : $('#no-result').show();
    });
});
</script>
</body>
</html>

 

항목 클릭 시 우측 영역에 상세 정보가 출력되는 로직.html
0.01MB

 

 

※ 해당 내용은 Google Gmini3.0에서 작성되었습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함