위젯 시스템

위젯 시스템

라이믹스 레이아웃에서 위젯을 활용하는 고급 기법을 학습합니다.

위젯 없이 최근게시물 출력

기본편 - 단일 게시판

<!-- 위젯 없이 최근게시물 코드 삽입하기 (기본편) -->
{@
    // 특정 게시판의 최근 게시물 가져오기
    $board_srl = 123; // 게시판 번호

    $args = new stdClass();
    $args->module_srl = $board_srl;
    $args->list_count = 5;
    $args->sort_index = 'list_order';
    $args->order_type = 'asc';
    $args->status = 'PUBLIC';

    $oDocumentModel = getModel('document');
    $output = $oDocumentModel->getDocumentList($args);
    $recent_documents = $output->data;
}

<div class="recent-posts">
    <h3>최근 게시물</h3>
    <ul class="post-list">
        <li loop="$recent_documents=>$document">
            <a href="{getUrl('', 'mid', 'board', 'document_srl', $document->document_srl)}">
                {$document->getTitle()}
                <span class="date">{$document->getRegdate('m.d')}</span>
            </a>
        </li>
    </ul>
</div>

활용편 - 다중 게시판

<!-- 위젯 없이 최근게시물 코드 삽입하기 (활용편) -->
{@
    // 여러 게시판의 최근 게시물 통합
    $board_srls = array(123, 456, 789); // 게시판 번호들

    $args = new stdClass();
    $args->module_srl = $board_srls;
    $args->list_count = 10;
    $args->sort_index = 'regdate';
    $args->order_type = 'desc';
    $args->status = array('PUBLIC', 'SECRET');

    // 카테고리 필터
    $args->category_srl = 111; // 특정 카테고리만

    // 확장변수 필터
    $args->extra_vars = array(
        'product_type' => 'featured'
    );

    $oDocumentModel = getModel('document');
    $output = $oDocumentModel->getDocumentList($args);
    $documents = $output->data;

    // 게시판 정보 미리 로드
    $module_info = array();
    $oModuleModel = getModel('module');
    foreach($board_srls as $module_srl) {
        $module_info[$module_srl] = $oModuleModel->getModuleInfoByModuleSrl($module_srl);
    }
}

<div class="integrated-recent">
    <h3>전체 최신글</h3>

    <table class="recent-table">
        <thead>
            <tr>
                <th>게시판</th>
                <th>제목</th>
                <th>작성자</th>
                <th>날짜</th>
            </tr>
        </thead>
        <tbody>
            <tr loop="$documents=>$document">
                {@$board_info = $module_info[$document->get('module_srl')]}

                <td class="board-name">
                    <a href="{getUrl('', 'mid', $board_info->mid)}">
                        {$board_info->browser_title}
                    </a>
                </td>

                <td class="title">
                    <a href="{getUrl('', 'mid', $board_info->mid, 'document_srl', $document->document_srl)}">
                        {$document->getTitle()}
                        <span class="comment-count" cond="$document->getCommentCount()">
                            [{$document->getCommentCount()}]
                        </span>
                    </a>
                </td>

                <td class="author">{$document->getNickName()}</td>
                <td class="date">{$document->getRegdate('Y.m.d')}</td>
            </tr>
        </tbody>
    </table>
</div>

고급활용편 - 커스텀 쿼리

<!-- 위젯 없이 최근게시물 코드 삽입하기 (고급활용편) -->
{@
    // 복잡한 조건의 게시물 가져오기
    $args = new stdClass();
    $args->module_srl = array(123, 456, 789);
    $args->list_count = 20;
    $args->page = 1;

    // 기간 조건 (최근 7일)
    $args->start_date = date('YmdHis', strtotime('-7 days'));
    $args->end_date = date('YmdHis');

    // 추천수 조건
    $args->voted_count = 5; // 5개 이상

    // 검색 조건
    $args->search_target = 'title_content';
    $args->search_keyword = '라이믹스';

    // 제외할 문서
    $args->exclude_document = array(111, 222, 333);

    // 회원 그룹 필터
    $args->member_group = array(1, 2); // 특정 그룹 회원의 글만

    // 직접 쿼리 실행
    $output = executeQuery('document.getDocumentList', $args);
    $documents = $output->data;

    // 썸네일 미리 생성
    foreach($documents as $document) {
        if($document->thumbnailExists()) {
            $document->thumbnail = $document->getThumbnail(200, 150);
        }
    }
}

<div class="advanced-recent">
    <h3>인기 게시물 (최근 7일)</h3>

    <div class="grid-layout">
        <article loop="$documents=>$document" class="grid-item">
            <!-- 썸네일 -->
            <div class="thumbnail">
                <a href="{getUrl('', 'document_srl', $document->document_srl)}">
                    <img cond="$document->thumbnail" src="{$document->thumbnail}" alt="" />
                    <span cond="!$document->thumbnail" class="no-thumb">No Image</span>
                </a>
            </div>

            <!-- 내용 -->
            <div class="content">
                <h4 class="title">
                    <a href="{getUrl('', 'document_srl', $document->document_srl)}">
                        {$document->getTitle()}
                    </a>
                </h4>

                <p class="excerpt">
                    {$document->getSummary(100)}
                </p>

                <div class="meta">
                    <span class="author">{$document->getNickName()}</span>
                    <span class="voted">추천 {$document->get('voted_count')}</span>
                </div>
            </div>
        </article>
    </div>
</div>

전체 코멘트 출력

최근 댓글 위젯

<!-- 전체 코멘트 출력하기 -->
{@
    // 최근 댓글 가져오기
    $args = new stdClass();
    $args->list_count = 10;
    $args->sort_index = 'list_order';
    $args->order_type = 'asc';

    // 특정 모듈만
    $args->module_srl = array(123, 456, 789);

    // 비밀댓글 제외
    $args->is_secret = 'N';

    $oCommentModel = getModel('comment');
    $output = $oCommentModel->getTotalCommentList($args);
    $comment_list = $output->data;

    // 문서 정보 미리 로드
    $document_srls = array();
    foreach($comment_list as $comment) {
        $document_srls[] = $comment->document_srl;
    }

    $oDocumentModel = getModel('document');
    $documents = $oDocumentModel->getDocuments($document_srls);
}

<div class="recent-comments">
    <h3>최근 댓글</h3>

    <ul class="comment-list">
        <li loop="$comment_list=>$comment">
            {@$document = $documents[$comment->document_srl]}

            <div class="comment-item">
                <!-- 프로필 이미지 -->
                <div class="profile">
                    {@$profile_image = $comment->getProfileImage()}
                    <img cond="$profile_image" src="{$profile_image->src}" alt="" />
                    <span cond="!$profile_image" class="no-profile">
                        {substr($comment->getNickName(), 0, 1)}
                    </span>
                </div>

                <!-- 댓글 내용 -->
                <div class="comment-content">
                    <div class="meta">
                        <strong>{$comment->getNickName()}</strong>
                        <span class="date">{$comment->getRegdate('m.d H:i')}</span>
                    </div>

                    <p class="text">
                        {$comment->getSummary(50)}
                    </p>

                    <a href="{getUrl('', 'mid', $document->mid, 'document_srl', $comment->document_srl)}#comment_{$comment->comment_srl}" 
                       class="link">
                        on "{$document->getTitle()}"
                    </a>
                </div>
            </div>
        </li>
    </ul>
</div>

탭형 최근게시물

카테고리별 탭

<!-- 탭형 최근게시물 출력 -->
{@
    // 카테고리별로 게시물 가져오기
    $board_module_srl = 123;
    $categories = array(
        array('srl' => 111, 'title' => '공지사항'),
        array('srl' => 222, 'title' => '자유게시판'),
        array('srl' => 333, 'title' => 'Q&A')
    );

    $tab_data = array();
    foreach($categories as $idx => $category) {
        $args = new stdClass();
        $args->module_srl = $board_module_srl;
        $args->category_srl = $category['srl'];
        $args->list_count = 5;
        $args->sort_index = 'regdate';
        $args->order_type = 'desc';

        $output = executeQuery('document.getDocumentList', $args);
        $tab_data[$idx] = array(
            'category' => $category,
            'documents' => $output->data
        );
    }
}

<div class="tab-widget">
    <!-- 탭 네비게이션 -->
    <ul class="tab-nav">
        <li loop="$tab_data=>$idx,$data" class="active"|cond="$idx==0">
            <a href="#tab-{$idx}" data-tab="{$idx}">
                {$data['category']['title']}
            </a>
        </li>
    </ul>

    <!-- 탭 콘텐츠 -->
    <div class="tab-content">
        <div loop="$tab_data=>$idx,$data" id="tab-{$idx}" class="tab-pane active"|cond="$idx==0">
            <ul class="doc-list">
                <li loop="$data['documents']=>$document">
                    <a href="{getUrl('', 'document_srl', $document->document_srl)}">
                        <span class="title">{$document->getTitle()}</span>
                        <span class="date">{$document->getRegdate('m.d')}</span>
                    </a>
                </li>
            </ul>

            <!-- 더보기 -->
            <a href="{getUrl('', 'mid', 'board', 'category', $data['category']['srl'])}" class="more-link">
                더보기 →
            </a>
        </div>
    </div>
</div>

<script>
// 탭 전환
$('.tab-nav a').click(function(e) {
    e.preventDefault();

    var tab = $(this).data('tab');

    // 네비게이션 활성화
    $('.tab-nav li').removeClass('active');
    $(this).parent().addClass('active');

    // 콘텐츠 전환
    $('.tab-pane').removeClass('active');
    $('#tab-' + tab).addClass('active');
});
</script>

동적 브레드크럼

<!-- 현재위치출력하기(breadcrumb) -->
{@
    // 브레드크럼 데이터 생성
    $breadcrumb = array();

    // 홈
    $breadcrumb[] = array(
        'title' => '홈',
        'url' => getUrl('')
    );

    // 현재 모듈 정보
    if($mid && $module_info) {
        // 메뉴 정보 가져오기
        $oMenuAdminModel = getAdminModel('menu');
        $menu_info = $oMenuAdminModel->getMenuItemInfo($module_info->menu_srl);

        // 상위 메뉴가 있으면 추가
        if($menu_info->parent_srl) {
            $parent_menu = $oMenuAdminModel->getMenuItemInfo($menu_info->parent_srl);
            $breadcrumb[] = array(
                'title' => $parent_menu->name,
                'url' => $parent_menu->url
            );
        }

        // 현재 메뉴
        $breadcrumb[] = array(
            'title' => $module_info->browser_title ?: $module_info->mid,
            'url' => getUrl('', 'mid', $module_info->mid)
        );
    }

    // 문서 보기
    if($document_srl && $oDocument && $oDocument->isExists()) {
        // 카테고리가 있으면 추가
        if($oDocument->get('category_srl')) {
            $category_info = $oDocumentModel->getCategory($oDocument->get('category_srl'));
            $breadcrumb[] = array(
                'title' => $category_info->title,
                'url' => getUrl('', 'mid', $mid, 'category', $oDocument->get('category_srl'))
            );
        }

        // 문서 제목
        $breadcrumb[] = array(
            'title' => $oDocument->getTitle(),
            'url' => getUrl('', 'mid', $mid, 'document_srl', $document_srl)
        );
    }
}

<nav class="breadcrumb" aria-label="현재 위치">
    <ol class="breadcrumb-list">
        <li loop="$breadcrumb=>$idx,$item" class="breadcrumb-item">
            <!-- 마지막 항목이 아닌 경우 링크 -->
            <a cond="$idx < count($breadcrumb) - 1" href="{$item['url']}">
                {$item['title']}
            </a>

            <!-- 마지막 항목은 텍스트만 -->
            <span cond="$idx == count($breadcrumb) - 1" aria-current="page">
                {$item['title']}
            </span>
        </li>
    </ol>
</nav>

<style>
.breadcrumb-list {
    display: flex;
    list-style: none;
    padding: 10px 0;
    margin: 0;
    font-size: 14px;
}

.breadcrumb-item:not(:last-child)::after {
    content: "›";
    margin: 0 10px;
    color: #999;
}

.breadcrumb-item a {
    color: #666;
    text-decoration: none;
}

.breadcrumb-item a:hover {
    color: #333;
    text-decoration: underline;
}

.breadcrumb-item:last-child {
    color: #333;
    font-weight: 500;
}
</style>

공지사항 세로롤링 위젯

자동 롤링 공지사항

<!-- 공지사항 세로롤링 위젯 만들기 -->
{@
    // 공지사항 가져오기
    $args = new stdClass();
    $args->module_srl = 123; // 공지사항 게시판
    $args->list_count = 10;
    $args->sort_index = 'regdate';
    $args->order_type = 'desc';
    $args->is_notice = 'Y'; // 공지사항만

    $output = executeQuery('document.getDocumentList', $args);
    $notices = $output->data;
}

<div class="notice-roller">
    <div class="roller-header">
        <h4>공지사항</h4>
        <a href="{getUrl('', 'mid', 'notice')}" class="more">더보기</a>
    </div>

    <div class="roller-container">
        <ul class="roller-list">
            <li loop="$notices=>$notice" class="roller-item">
                <a href="{getUrl('', 'mid', 'notice', 'document_srl', $notice->document_srl)}">
                    <span class="label">공지</span>
                    <span class="title">{$notice->getTitle()}</span>
                    <span class="date">{$notice->getRegdate('m.d')}</span>
                </a>
            </li>
        </ul>
    </div>

    <!-- 컨트롤 버튼 -->
    <div class="roller-controls">
        <button type="button" class="btn-prev" title="이전">
            <i class="xi-angle-up"></i>
        </button>
        <button type="button" class="btn-pause" title="일시정지">
            <i class="xi-pause"></i>
        </button>
        <button type="button" class="btn-next" title="다음">
            <i class="xi-angle-down"></i>
        </button>
    </div>
</div>

<script>
(function($) {
    var $roller = $('.roller-list');
    var $items = $roller.find('.roller-item');
    var itemHeight = $items.first().outerHeight();
    var currentIndex = 0;
    var isPaused = false;
    var timer;

    // 자동 롤링
    function startRolling() {
        timer = setInterval(function() {
            if(!isPaused) {
                rollNext();
            }
        }, 3000);
    }

    // 다음 항목으로 롤링
    function rollNext() {
        currentIndex = (currentIndex + 1) % $items.length;
        $roller.animate({
            marginTop: -currentIndex * itemHeight
        }, 500);
    }

    // 이전 항목으로 롤링
    function rollPrev() {
        currentIndex = currentIndex > 0 ? currentIndex - 1 : $items.length - 1;
        $roller.animate({
            marginTop: -currentIndex * itemHeight
        }, 500);
    }

    // 컨트롤 버튼
    $('.btn-next').click(function() {
        clearInterval(timer);
        rollNext();
        startRolling();
    });

    $('.btn-prev').click(function() {
        clearInterval(timer);
        rollPrev();
        startRolling();
    });

    $('.btn-pause').click(function() {
        isPaused = !isPaused;
        $(this).find('i').toggleClass('xi-pause xi-play');
    });

    // 마우스 오버시 일시정지
    $('.roller-container').hover(
        function() { isPaused = true; },
        function() { isPaused = false; }
    );

    // 시작
    startRolling();
})(jQuery);
</script>

<style>
.notice-roller {
    border: 1px solid #ddd;
    border-radius: 5px;
    overflow: hidden;
}

.roller-container {
    height: 40px;
    overflow: hidden;
    position: relative;
}

.roller-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.roller-item {
    height: 40px;
    line-height: 40px;
    padding: 0 15px;
}

.roller-item .label {
    background: #ff4444;
    color: white;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 12px;
    margin-right: 10px;
}

.roller-controls {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    gap: 5px;
}

.roller-controls button {
    width: 24px;
    height: 24px;
    border: 1px solid #ddd;
    background: white;
    border-radius: 3px;
    cursor: pointer;
}
</style>

모범 사례

  1. 성능 최적화: 필요한 데이터만 쿼리
  2. 캐싱 활용: 자주 사용되는 데이터는 캐싱
  3. 에러 처리: 데이터가 없을 때 처리
  4. 반응형 대응: 모바일에서도 잘 보이도록
  5. 접근성: ARIA 레이블, 키보드 네비게이션

다음 단계

위젯 시스템을 마스터했다면, 메타태그와 SEO를 학습하세요.