open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { throw new Exception("ZIP 생성 실패: {$zipPath}"); } $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST ); foreach ($iterator as $file) { $filePath = $file->getPathname(); $localPath = substr($filePath, strlen($sourceDir) + 1); if ($file->isDir()) { $zip->addEmptyDir($localPath); } else { $zip->addFile($filePath, $localPath); } } $zip->close(); } try { $root = __DIR__; $themeRoot = $root . '/theme/journal'; // --------------------------- // 1) 테마 기본 파일 // --------------------------- put_file($themeRoot.'/theme.config.php', <<<'PHP' ', 0); add_stylesheet('', 1); add_javascript('', 0); include_once(G5_THEME_PATH.'/parts/header/header.php'); PHP ); put_file($themeRoot.'/tail.php', <<<'PHP'
PHP ); put_file($themeRoot.'/parts/main/main.php', <<<'PHP'
Hero

HEADLINE

메인 헤드라인 영역(연동 전)

이 영역은 ‘가장 최신/중요 기사 1건’을 연결하세요.

YYYY-MM-DD Category
전체 기사 보기

VOL. 384 | Monthly Laser Technology

과월호 보기
thumb

Editor’s Pick

이번 호 추천 기사

요약문 자리(2~3줄)

YYYY-MM-DDCategory
'focus', 'title'=>'포커스', 'sub'=>'Industry Focus'), array('id'=>'interview', 'title'=>'인터뷰', 'sub'=>'Interviews'), array('id'=>'market', 'title'=>'레이저시장', 'sub'=>'Laser Market'), array('id'=>'trend', 'title'=>'관련산업동향', 'sub'=>'Industry Trend'), array('id'=>'photo', 'title'=>'포토이슈', 'sub'=>'Photo Issue'), array('id'=>'tech', 'title'=>'신기술', 'sub'=>'New Technology'), array('id'=>'product', 'title'=>'신제품', 'sub'=>'New Products'), ); ?>
thumb

기사

요약문 자리(2~3줄)

YYYY-MM-DD
PHP ); put_file($themeRoot.'/parts/footer/footer.php', <<<'PHP' PHP ); // --------------------------- // 3) assets: css/js/img(svg) // --------------------------- put_file($themeRoot.'/assets/css/journal.base.css', <<<'CSS' .jrnl { color:#111; font-family: system-ui, -apple-system, Segoe UI, Roboto, "Noto Sans KR", sans-serif; } .jrnl * { box-sizing: border-box; } .jrnl a { color: inherit; text-decoration: none; } .jrnl img { max-width:100%; display:block; } .jrnl__container { width: min(1200px, calc(100% - 32px)); margin:0 auto; } .jrnl__btn { display:inline-block; padding:10px 14px; border:1px solid #111; background:#111; color:#fff; border-radius:10px; } CSS ); put_file($themeRoot.'/assets/css/journal.layout.css', <<<'CSS' #jrnl-header .jrnl__topbar { background:#f6f6f6; font-size:14px; } #jrnl-header .jrnl__utility { display:flex; gap:12px; justify-content:flex-end; padding:8px 0; } #jrnl-header .jrnl__gnb { border-bottom:1px solid #eee; background:#fff; } #jrnl-header .jrnl__gnbRow { display:flex; align-items:center; gap:16px; padding:14px 0; } #jrnl-header .jrnl__nav { display:flex; gap:14px; margin-left:auto; } #jrnl-header .jrnl__menuBtn { display:none; margin-left:auto; } #jrnl-main .jrnl__hero { padding:22px 0; background:#0b0f17; border-bottom:1px solid #111; } #jrnl-main .jrnl__heroGrid { display:grid; grid-template-columns: 1.6fr 1fr; gap:18px; } #jrnl-main .jrnl__heroCard { background:#101827; border:1px solid rgba(255,255,255,.08); border-radius:12px; overflow:hidden; color:#fff; } #jrnl-main .jrnl__heroThumb { background:#05070c; } #jrnl-main .jrnl__heroBody { padding:16px; } #jrnl-main .jrnl__kicker { margin:0 0 6px; font-size:12px; letter-spacing:.08em; color:rgba(255,255,255,.7); } #jrnl-main .jrnl__heroTitle { margin:0 0 8px; font-size:28px; line-height:1.2; } #jrnl-main .jrnl__heroLead { margin:0 0 10px; color:rgba(255,255,255,.85); } #jrnl-main .jrnl__meta { display:flex; gap:10px; font-size:12px; color:rgba(255,255,255,.7); } #jrnl-main .jrnl__btn { background:#fff; color:#111; border-color:#fff; } #jrnl-main .jrnl__latest { background:#0f172a; border:1px solid rgba(255,255,255,.08); border-radius:12px; padding:16px; color:#fff; } #jrnl-main .jrnl__latestList { list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:10px; } #jrnl-main .jrnl__latestItem a { display:flex; justify-content:space-between; gap:12px; color:#fff; } #jrnl-main .jrnl__latestTitle { color:rgba(255,255,255,.9); } #jrnl-main .jrnl__latestDate { color:rgba(255,255,255,.6); font-size:12px; } #jrnl-main .jrnl__issue { padding:28px 0; background:#fff; } #jrnl-main .jrnl__sections { padding:10px 0 40px; background:#fff; } #jrnl-main .jrnl__block { padding:22px 0; border-top:1px solid #eee; } #jrnl-main .jrnl__sectionHead { display:flex; align-items:flex-end; justify-content:space-between; gap:12px; margin-bottom:12px; } #jrnl-main .jrnl__sectionSub { margin:0; color:#666; font-size:13px; } #jrnl-main .jrnl__cardGrid { display:grid; grid-template-columns: repeat(3, 1fr); gap:16px; } #jrnl-main .jrnl__card { border:1px solid #eee; border-radius:12px; overflow:hidden; background:#fff; } #jrnl-main .jrnl__thumb { background:#f2f2f2; } #jrnl-main .jrnl__body { padding:14px; } #jrnl-main .jrnl__tag { margin:0 0 6px; font-size:12px; color:#666; } #jrnl-main .jrnl__title { margin:0 0 8px; font-size:18px; line-height:1.3; } #jrnl-main .jrnl__excerpt { margin:0 0 10px; color:#444; font-size:14px; line-height:1.5; } #jrnl-main .jrnl__meta { display:flex; gap:10px; font-size:12px; color:#777; } #jrnl-footer { border-top:1px solid #eee; background:#fff; padding:26px 0; } #jrnl-footer .jrnl__cta { border:1px solid #eee; border-radius:12px; padding:16px; background:#fafafa; margin-bottom:14px; } #jrnl-footer .jrnl__footerMeta { display:flex; flex-wrap:wrap; gap:12px; align-items:center; justify-content:space-between; } #jrnl-footer .jrnl__copy { margin:0; color:#666; font-size:13px; } @media (max-width: 1024px) { #jrnl-main .jrnl__heroGrid { grid-template-columns: 1fr; } #jrnl-main .jrnl__cardGrid { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 640px) { #jrnl-header .jrnl__nav { display:none; } #jrnl-header .jrnl__menuBtn { display:inline-block; } #jrnl-main .jrnl__cardGrid { grid-template-columns: 1fr; } } CSS ); put_file($themeRoot.'/assets/js/journal.base.js', <<<'JS' (function () { const btn = document.querySelector('[data-jrnl="menu-toggle"]'); const nav = document.querySelector('[data-jrnl="nav"]'); if (!btn || !nav) return; btn.addEventListener('click', () => { const isOpen = nav.style.display === 'flex'; nav.style.display = isOpen ? 'none' : 'flex'; nav.style.flexDirection = 'column'; nav.style.gap = '10px'; }); })(); JS ); // 로고 SVG put_file($themeRoot.'/assets/img/logo.svg', <<<'SVG' LaserWorld SVG ); // 메인 히어로 이미지 (SVG) put_file($themeRoot.'/assets/img/hero-laser.svg', <<<'SVG' Laser Industry Journal Latest news + in-depth features, optimized for responsive layouts. SVG ); // 카드용 플레이스홀더 이미지 (SVG) put_file($themeRoot.'/assets/img/card-placeholder.svg', <<<'SVG' Thumbnail 16:9 placeholder SVG ); // --------------------------- // 4) 게시판 공용 스킨 // --------------------------- $skinRoot = $themeRoot.'/skin/board/journal_board'; put_file($skinRoot.'/style.css', <<<'CSS' .jrnl-board .jrnl-board__head { display:flex; justify-content:space-between; align-items:flex-end; gap:12px; margin:18px 0; } .jrnl-board .jrnl-board__title { margin:0; font-size:26px; } .jrnl-board .jrnl-board__list { display:grid; grid-template-columns:repeat(3, 1fr); gap:16px; } .jrnl-board .jrnl-board__item { border:1px solid #eee; border-radius:12px; overflow:hidden; background:#fff; } .jrnl-board .jrnl-board__thumb { aspect-ratio:16/9; background:#ddd; overflow:hidden; } .jrnl-board .jrnl-board__thumb img { width:100%; height:100%; object-fit:cover; } .jrnl-board .jrnl-board__body { padding:14px; } .jrnl-board .jrnl-board__meta { font-size:12px; color:#777; display:flex; gap:10px; margin-bottom:8px; } .jrnl-board .jrnl-board__subject { margin:0 0 8px; font-size:18px; line-height:1.3; } .jrnl-board .jrnl-board__excerpt { margin:0; color:#444; font-size:14px; line-height:1.5; } @media (max-width:1024px){ .jrnl-board .jrnl-board__list { grid-template-columns:repeat(2, 1fr); } } @media (max-width:640px){ .jrnl-board .jrnl-board__list { grid-template-columns:1fr; } } CSS ); put_file($skinRoot.'/list.skin.php', <<<'PHP' ', 50); ?>
= 120) $excerpt .= '...'; // 썸네일은 연동 시 get_list_thumbnail()로 교체 권장 $fallback = G5_THEME_URL.'/assets/img/card-placeholder.svg'; ?>
PHP ); // --------------------------- // 5) ZIP 생성 // --------------------------- zip_dir($themeRoot, $root.'/theme-journal.zip'); zip_dir($skinRoot, $root.'/skin-journal_board.zip'); header('Content-Type: text/plain; charset=utf-8'); echo "완료!\n"; echo "- 생성: theme/journal\n"; echo "- 생성: theme-journal.zip\n"; echo "- 생성: skin-journal_board.zip\n"; echo "\n주의: install_journal_theme.php 파일은 실행 후 삭제하세요.\n"; } catch (Exception $e) { header('Content-Type: text/plain; charset=utf-8'); echo "오류: ".$e->getMessage()."\n"; }