레이아웃 만들기

레이아웃 만들기

레이아웃이란?

레이아웃은 웹사이트의 전체적인 구조와 디자인을 담당하는 템플릿입니다. 모든 페이지에 공통으로 적용되는 헤더, 푸터, 사이드바 등을 포함합니다.

레이아웃 기본 구조

필수 파일

layouts/
└── my_layout/
    ├── conf/
    │   └── info.xml        # 레이아웃 정보
    ├── layout.html         # 메인 레이아웃 파일
    ├── layout.css          # 스타일시트
    └── layout.js           # 자바스크립트 (선택)

info.xml 작성

<?xml version="1.0" encoding="UTF-8"?>
<layout version="0.2">
    <title xml:lang="ko">나의 레이아웃</title>
    <description xml:lang="ko">커스텀 레이아웃입니다.</description>
    <version>1.0</version>
    <date>2024-01-01</date>
    <author email="user@example.com" link="https://example.com">
        <name xml:lang="ko">제작자명</name>
    </author>
    <license>MIT</license>

    <!-- 레이아웃 설정 변수 -->
    <extra_vars>
        <var name="logo_image" type="image">
            <title xml:lang="ko">로고 이미지</title>
            <description xml:lang="ko">상단에 표시될 로고 이미지</description>
        </var>
        <var name="colorset" type="select">
            <title xml:lang="ko">컬러셋</title>
            <options value="default">
                <title xml:lang="ko">기본</title>
            </options>
            <options value="dark">
                <title xml:lang="ko">다크</title>
            </options>
        </var>
    </extra_vars>

    <!-- 메뉴 설정 -->
    <menus>
        <menu name="main_menu" maxdepth="3" default="true">
            <title xml:lang="ko">메인 메뉴</title>
        </menu>
        <menu name="footer_menu" maxdepth="1">
            <title xml:lang="ko">푸터 메뉴</title>
        </menu>
    </menus>
</layout>

layout.html 기본 구조

<!-- 레이아웃 설정 변수 초기화 -->
{@
    // 레이아웃 정보를 짧은 변수로
    $li = $layout_info;

    // 메인 페이지 여부 체크
    $is_index = ($mid == 'index' && !$act) || ($site_module_info->module_srl === $current_module_info->module_srl && !$act);

    // 로그인 여부
    $is_logged = $logged_info ? true : false;
}

<!-- CSS 로드 -->
<load target="layout.css" />
<load target="layout.js" />

<!-- 레이아웃 시작 -->
<div id="wrap" class="colorset-{$li->colorset ?: 'default'}">
    <!-- 헤더 -->
    <header id="header">
        <div class="container">
            <!-- 로고 -->
            <h1 class="logo">
                <a href="{getUrl()}">
                    <!--@if($li->logo_image)-->
                        <img src="{$li->logo_image}" alt="{$layout_info->site_title}" />
                    <!--@else-->
                        {$layout_info->site_title}
                    <!--@endif-->
                </a>
            </h1>

            <!-- 메인 메뉴 -->
            <nav class="gnb">
                <ul>
                    <li loop="$main_menu->list => $key1, $val1" class="active"|cond="$val1['selected']">
                        <a href="{$val1['href']}" target="_blank"|cond="$val1['open_window'] == 'Y'">
                            {$val1['link']}
                        </a>

                        <!-- 2차 메뉴 -->
                        <ul class="depth2" cond="$val1['list']">
                            <li loop="$val1['list'] => $key2, $val2" class="active"|cond="$val2['selected']">
                                <a href="{$val2['href']}">{$val2['link']}</a>
                            </li>
                        </ul>
                    </li>
                </ul>
            </nav>

            <!-- 사용자 메뉴 -->
            <div class="user-menu">
                <!--@if(!$is_logged)-->
                    <a href="{getUrl('act', 'dispMemberLoginForm')}">로그인</a>
                    <a href="{getUrl('act', 'dispMemberSignUpForm')}">회원가입</a>
                <!--@else-->
                    <a href="{getUrl('act', 'dispMemberInfo')}">{$logged_info->nick_name}</a>
                    <a href="{getUrl('act', 'dispMemberLogout')}">로그아웃</a>
                    <a href="{getUrl('', 'module', 'admin')}" cond="$logged_info->is_admin == 'Y'">관리</a>
                <!--@endif-->
            </div>
        </div>
    </header>

    <!-- 콘텐츠 영역 -->
    <main id="content">
        <div class="container">
            <!--@if($is_index)-->
                <!-- 메인 페이지 콘텐츠 -->
                <include target="index.html" />
            <!--@else-->
                <!-- 모듈 콘텐츠 -->
                {$content}
            <!--@endif-->
        </div>
    </main>

    <!-- 푸터 -->
    <footer id="footer">
        <div class="container">
            <!-- 푸터 메뉴 -->
            <nav class="footer-menu" cond="$footer_menu">
                <ul>
                    <li loop="$footer_menu->list => $key, $val">
                        <a href="{$val['href']}">{$val['link']}</a>
                    </li>
                </ul>
            </nav>

            <!-- 저작권 -->
            <p class="copyright">
                Copyright © {date('Y')} {$layout_info->site_title}. All rights reserved.
            </p>
        </div>
    </footer>
</div>

주요 변수들

시스템 변수

  • $content: 각 모듈에서 생성된 콘텐츠
  • $module_info: 현재 모듈 정보
  • $logged_info: 로그인한 회원 정보
  • $layout_info: 레이아웃 설정 정보
  • $lang: 언어 변수

메뉴 변수

  • $main_menu->list: 메인 메뉴 목록
  • $main_menu->maxdepth: 최대 깊이
  • 각 메뉴 항목의 속성:
  • href: 링크 URL
  • link: 메뉴 텍스트
  • selected: 선택 여부
  • list: 하위 메뉴
  • open_window: 새 창 열기 여부

반응형 레이아웃

뷰포트 설정

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

미디어 쿼리

/* layout.css */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px;
}

/* 태블릿 */
@media (max-width: 768px) {
    .gnb .depth2 {
        position: static;
    }
}

/* 모바일 */
@media (max-width: 480px) {
    .gnb {
        display: none;
    }

    .mobile-menu {
        display: block;
    }
}

모바일 체크

{@
    // 모바일 여부 체크
    $is_mobile = Mobile::isFromMobilePhone();
}

<!--@if($is_mobile)-->
    <load target="mobile.css" />
<!--@endif-->

위젯 영역 추가

위젯 코드 생성기 사용

<!-- 위젯 영역 -->
<div class="widget-area">
    <img class="zbxe_widget_output" widget="content" skin="default" colorset="white" content_type="document" module_srls="64" list_type="normal" tab_type="none" markup_type="list" list_count="5" cols_list_count="1" page_count="1" option_view="title,regdate,nickname" show_browser_title="Y" show_comment_count="Y" show_trackback_count="Y" show_category="Y" show_icon="Y" order_target="list_order" order_type="desc" />
</div>

위젯 캐시 설정

위젯 성능 향상을 위해 캐시 설정 가능:

<img class="zbxe_widget_output" widget="content" cache="300" ... />

고급 기능

사이트맵 자동 생성

<div class="sitemap">
    <ul>
        <li loop="$main_menu->list => $key1, $val1">
            <h3><a href="{$val1['href']}">{$val1['link']}</a></h3>
            <ul cond="$val1['list']">
                <li loop="$val1['list'] => $key2, $val2">
                    <a href="{$val2['href']}">{$val2['link']}</a>
                </li>
            </ul>
        </li>
    </ul>
</div>

브레드크럼 (현재 위치)

<nav class="breadcrumb">
    <a href="{getUrl()}">홈</a>
    <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected']">
        <span>&gt;</span>
        <a href="{$val1['href']}">{$val1['link']}</a>
        <block loop="$val1['list'] => $key2, $val2" cond="$val2['selected']">
            <span>&gt;</span>
            <a href="{$val2['href']}">{$val2['link']}</a>
        </block>
    </block>
</nav>

디버깅 팁

  1. 레이아웃 변수 확인
<!--@if(__DEBUG__)-->
<pre>{var_dump($layout_info)}</pre>
<!--@endif-->
  1. 메뉴 구조 확인
<!--@if(__DEBUG__)-->
<pre>{print_r($main_menu->list, true)}</pre>
<!--@endif-->
  1. 캐시 문제 해결
    - files/cache/ 디렉토리 삭제
    - 관리자 > 캐시 파일 재생성