Files
dnssash/theme/rd.laser/rb.layout/laser/index.php
T
2026-06-11 18:47:38 +09:00

612 lines
26 KiB
PHP

<?php
if (!defined('_GNUBOARD_')) exit;
add_stylesheet('<link rel="stylesheet" href="'.G5_THEME_URL.'/rb.layout/'.$rb_core['layout'].'/style.css">', 0);
//add_stylesheet('<link rel="stylesheet" href="'.G5_THEME_URL.'/rb.layout/laser.TLRB/style.css">', 0);
// ==============================================================================
// [설정 영역] 이곳의 변수만 변경하면 전체 내용이 적용됩니다.
// ==============================================================================
// 💡 [추가] Hero 섹션 우측 바로가기 박스 표시 여부 (true: 보임, false: 숨김)
$show_hero_visual = false;
function get_bo_table_from_url_regex_index($url) {
if (preg_match('/bo_table=([^&]+)/', $url, $matches)) {
return $matches[1];
}
return '';
}
// 동적 데이터 생성 로직
$hero_box_config = [];
$board_groups = [];
$icons = ['📊', '🔬', '🆕', '📅', '📷', '💡', '📦']; // 아이콘 목록
$hero_box_config[] = [
'title' =>'정기 구독 & 광고 문의',
'icon' => $icons[5] ?? '📄',
'bo_table' => '정기구독',
'desc' => '정기 구독 & 광고 문의'
];
// 메뉴 데이터 가져오기 (그누보드 공통 함수 사용)
$menu_datas = get_menu_db(0, false);
foreach ($menu_datas as $i=> $row) {
if($i===1 || $i===2) {
foreach ($row['sub'] as $sub) {
$menu_name = $sub['me_name'];
list($sub_ko, $sub_en) = split_menu_name($sub['me_name']);
$menu_name = $sub_ko . '<br>'. $sub_en;
$board_name = get_bo_table_from_url_regex_index($sub['me_link']);
$board_groups[$board_name] = [
'bo_table' => $board_name,
'title' => $menu_name,
'latest_rows' => 5,
'latest_subject_len' => 10,
];
}
}
}
// 💡 [수정] 레이아웃 그리드 설정 (다차원 배열 구조)
// 각 행(row) 안에 열(columns)을 정의하고, 각 열 안에 행(rows) 개수를 정의합니다.
$layout_grid_config = [
'top' => [
'columns' => [
['rows' => 1], // 1번 열: 1행 (통짜)
['rows' => 2], // 2번 열: 2행 (상하 분할)
]
],
'middle' => [
'columns' => [
['rows' => 2], // 1번 열: 2행
['rows' => 2], // 2번 열: 2행
],
],
'bottom' => [
'columns' => [
['rows' => 1] // 1번 열: 1행 (통짜)
]
]
];
?>
<div class="creative-portfolio-container">
<section class="hero-section">
<div class="hero-background">
<img src="<?php echo G5_THEME_URL ?>/rb.layout/laser/img/main.png" alt="Laser Technology 2026" class="bg-img">
<div class="hero-overlay"></div>
</div>
<div class="hero-text">
<!-- <span class="hero-badge">Vol. 384 | MONTHLY LASER TECHNOLOGY</span>-->
<?php
// 💡 [수정] DB 연동: 그누보드 기본환경설정 여분필드 2번(cf_2) 사용
// 관리자 > 환경설정 > 기본환경설정 > 여분필드 2번에 입력된 값을 출력
// 값이 없으면 기본 텍스트 출력
$hero_title_line = (isset($config['cf_1']) && $config['cf_1']) ? nl2br($config['cf_1']) : '2026 레이저 산업';
$hero_title_line_text = (isset($config['cf_2']) && $config['cf_2']) ? nl2br($config['cf_2']) : '전시 지형이 움직인다';
?>
<h1 class="hero-title">
<span class="title-line"> <?php echo $hero_title_line; ?></span>
<span class="title-line gradient-text"><?php echo $hero_title_line_text; ?></span>
</h1>
<?php
// 💡 [수정] DB 연동: 그누보드 기본환경설정 여분필드 2번(cf_2) 사용
// 관리자 > 환경설정 > 기본환경설정 > 여분필드 2번에 입력된 값을 출력
// 값이 없으면 기본 텍스트 출력
$hero_subtitle = (isset($config['cf_3']) && $config['cf_3']) ? nl2br($config['cf_3']) : '기술 경쟁에서 시장 전략으로, 국내 전시회의 재조명.<br>월간 레이저 기술이 제안하는 2026년 산업 로드맵을 확인하십시오.';
$hero_subtitle_but = (isset($config['cf_4']) && $config['cf_4']) ? $config['cf_4'] : '#journal-list';
// 💡 [추가] URL 도메인 자동 보정 로직
// 저장된 URL이 http:// 또는 https:// 로 시작하는 경우, 현재 접속한 도메인으로 교체합니다.
if (preg_match('/^https?:\/\/[^\/]+(.*)$/i', $hero_subtitle_but, $matches)) {
// $matches[1]은 도메인 이후의 경로 (예: /bbs/board.php?bo_table=...)
// 현재 접속 프로토콜과 도메인을 가져옴
$current_domain = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'];
$hero_subtitle_but = $current_domain . $matches[1];
}
?>
<p class="hero-subtitle">
<?php echo $hero_subtitle; ?>
</p>
<div class="hero-cta">
<a href="<?php echo $hero_subtitle_but; ?>" class="btn-primary">전체 기사 보기</a>
</div>
</div>
<div class="hero-content">
<!-- 💡 [수정] 설정에 따라 hero-visual 표시 여부 결정 -->
<?php if ($show_hero_visual): ?>
<div class="hero-visual">
<div class="creative-showcase">
<?php foreach($hero_box_config as $i => $box): ?>
<?php if (empty($box['bo_table']) || $box['bo_table'] =='정기구독') :?>
<div class="showcase-item btn-open-contact-modal item-<?php echo $i; ?>" onclick="location.href='#'" style="cursor:pointer;"> <div class="item-content">
<div class="item-icon"><?php echo $box['icon']; ?></div>
<h4><?php echo $box['title']; ?></h4>
<span class="item-desc"><?php echo $box['desc']; ?></span>
</div>
</div>
<?php else: ?>
<div class="showcase-item item-<?php echo $i; ?>" onclick="location.href='<?php echo G5_BBS_URL ?>/board.php?bo_table=<?php echo $box['bo_table']; ?>'" style="cursor:pointer;">
<div class="item-content">
<div class="item-icon"><?php echo $box['icon']; ?></div>
<h4><?php echo $box['title']; ?></h4>
<span class="item-desc"><?php echo $box['desc']; ?></span>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
</section>
<section class="portfolio-section" id="journal-list">
<div class="container">
<div class="section-header">
<!-- <span class="section-badge">CONTENTS</span>-->
<?php
// 💡 [수정] DB 연동: 그누보드 기본환경설정 여분필드 1번(cf_1) 사용
// 관리자 > 환경설정 > 기본환경설정 > 여분필드 1번에 입력된 값을 출력
// 값이 없으면 기본값 '이달의 주요 섹션' 출력
$section_title = (isset($config['cf_5']) && $config['cf_5']) ? $config['cf_5'] : '이달의 주요 섹션';
?>
<h2 class="section-title"><?php echo $section_title; ?></h2>
<!-- <p class="section-subtitle">월간 레이저 기술 제384호 목차 구성</p>-->
</div>
<div class="portfolio-filter">
<button class="filter-btn active" data-filter="all">전체 보기</button>
<?php foreach($board_groups as $key => $group): ?>
<button class="filter-btn" data-filter="<?php echo $key; ?>"><?php echo $group['title']; ?></button>
<?php endforeach; ?>
</div>
<div class="portfolio-grid">
<?php
$all_items = []; // 모든 게시판의 아이템을 담을 배열
foreach($board_groups as $key => $group):
$bo_table = $group['bo_table'];
$write_table = $g5['write_prefix'] . $bo_table;
// wr_8 값이 있는 게시물만 조회 (최신순)
// wr_is_comment = 0 (댓글 제외)
$sql = " SELECT * FROM {$write_table} WHERE wr_is_comment = 0 AND wr_8 <> '' ORDER BY wr_id DESC LIMIT {$group['latest_rows']} ";
$result = sql_query($sql);
while ($row = sql_fetch_array($result)) {
$row['bo_table'] = $bo_table;
$row['group_key'] = $key;
$row['group_title'] = $group['title'];
$all_items[] = $row;
}
endforeach;
$cols = 4; // 한 줄에 보여줄 개수
$total_count = count($all_items);
// 첫 줄은 무조건 출력
$first_row_count = min($total_count, $cols);
for ($i = 0; $i < $first_row_count; $i++) {
$lt = $all_items[$i];
$thumb = get_list_thumbnail($lt['bo_table'], $lt['wr_id'], 400, 300);
$img_src = $thumb['src'] ? $thumb['src'] : G5_THEME_URL.'/img/no_img.png';
$link = get_pretty_url($lt['bo_table'], $lt['wr_id']);
$subject = $lt['wr_subject'];
$content = cut_str(strip_tags($lt['wr_content']), 80);
?>
<div class="portfolio-item" data-category="<?php echo $lt['group_key']; ?>" data-index="<?php echo $i; ?>">
<div class="portfolio-wrapper">
<div class="portfolio-image">
<img src="<?php echo $img_src; ?>" alt="<?php echo $subject; ?>">
</div>
<div class="portfolio-overlay">
<div class="overlay-content">
<span class="category-tag"><?php echo $lt['group_title']; ?></span>
<h3><?php echo $subject; ?></h3>
<p class="summary"><?php echo $content; ?></p>
<a href="<?php echo $link; ?>" class="btn-view">자세히 보기</a>
</div>
</div>
</div>
</div>
<?php
}
// 두 번째 줄부터 4의 배수 처리
if ($total_count > $cols) {
$remaining_items = array_slice($all_items, $cols);
$remaining_count = count($remaining_items);
$valid_count = floor($remaining_count / $cols) * $cols;
for ($i = 0; $i < $valid_count; $i++) {
$lt = $remaining_items[$i];
$thumb = get_list_thumbnail($lt['bo_table'], $lt['wr_id'], 400, 300);
$img_src = $thumb['src'] ? $thumb['src'] : G5_THEME_URL.'/img/no_img.png';
$link = get_pretty_url($lt['bo_table'], $lt['wr_id']);
$subject = $lt['wr_subject'];
$content = cut_str(strip_tags($lt['wr_content']), 80);
?>
<div class="portfolio-item" data-category="<?php echo $lt['group_key']; ?>" data-index="<?php echo $i + $cols; ?>">
<div class="portfolio-wrapper">
<div class="portfolio-image">
<img src="<?php echo $img_src; ?>" alt="<?php echo $subject; ?>">
</div>
<div class="portfolio-overlay">
<div class="overlay-content">
<span class="category-tag"><?php echo $lt['group_title']; ?></span>
<h3><?php echo $subject; ?></h3>
<p class="summary"><?php echo $content; ?></p>
<a href="<?php echo $link; ?>" class="btn-view">자세히 보기</a>
</div>
</div>
</div>
</div>
<?php
}
}
?>
</div>
</div>
</section>
<section class="process-section">
<div class="container">
<main class="layout-main-content1">
<?php foreach ($layout_grid_config as $row_name => $row_config): ?>
<!-- 행(Row) 시작 -->
<div class="layout-row layout-row-<?php echo $row_name; ?>">
<?php
$columns = $row_config['columns'];
$col_index = 1;
foreach ($columns as $col_config):
$row_count = isset($col_config['rows']) ? $col_config['rows'] : 1;
?>
<!-- 열(Column) 시작 -->
<div class="layout-col layout-col-<?php echo $col_index; ?>">
<?php for ($r = 1; $r <= $row_count; $r++): ?>
<!-- 내부 행(Inner Row) 시작 -->
<div class="flex_box layout-inner-row" data-layout="main-content-<?php echo $row_name; ?>-col<?php echo $col_index; ?>-row<?php echo $r; ?>">
</div>
<?php endfor; ?>
</div>
<?php
$col_index++;
endforeach;
?>
</div>
<!-- 행(Row) 끝 -->
<?php endforeach; ?>
</main>
</div>
</section>
<!-- <section class="cta-section">-->
<!-- <div class="container">-->
<!-- <a href="javascript:void(0);" class="btn-open-contact-modal open-contact-modal btn-secondary-large">정기 구독 신청 & 광고 게재 문의</a>-->
<!-- </div>-->
<!-- </section>-->
</div>
<script>
jQuery(document).ready(function($) {
/**
* $rowcount: 현재 선택된 필터 값을 저장하는 전역적 변수
* 초기값은 'all'로 설정하여 초기 로드 시 동작을 제어합니다.
*/
var $rowcount = "all";
/**
* 필터링 실행 함수
* @param {string} filterValue - 클릭된 버튼의 data-filter 값
*/
function applyDynamicFilter(filterValue) {
// 변수에 현재 필터 상태 저장 (요청하신 부분)
$rowcount = filterValue;
// 애니메이션 성능을 위해 현재 표시된 것들을 먼저 숨김
$('.portfolio-item').hide();
if ($rowcount === 'all') {
/**
* [전체 보기 모드]
* 전체 아이템을 모두 보여줍니다. (PHP에서 이미 4의 배수로 잘랐으므로 그대로 노출)
*/
$('.portfolio-item').stop().fadeIn(300);
} else {
/**
* [특정 카테고리 모드]
* 선택된 카테고리에 해당하는 아이템 전체(최대 5개) 노출
*/
$('.portfolio-item[data-category="' + $rowcount + '"]').stop().fadeIn(300);
}
// 콘솔을 통해 현재 $rowcount에 저장된 데이터 확인
console.log("현재 필터링 변수($rowcount) 상태: " + $rowcount);
}
// 필터 버튼 클릭 이벤트 핸들러
$('.filter-btn').on('click', function(e) {
e.preventDefault(); // 링크 이동 방지
var filterValue = $(this).attr('data-filter');
// 1. UI 변경: 활성화 버튼 표시
$('.filter-btn').removeClass('active');
$(this).addClass('active');
// 2. 필터 로직 실행
applyDynamicFilter(filterValue);
});
/**
* 페이지 로드 시 초기 실행
* 처음 접속 시 'all' 상태를 기준으로 각 섹션별 2개씩 노출합니다.
*/
applyDynamicFilter('all');
// 💡 [추가] 스크롤 애니메이션 (Intersection Observer)
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.2 // 20% 보일 때 실행
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
observer.unobserve(entry.target); // 한 번 실행 후 관찰 중지
}
});
}, observerOptions);
// 관찰 대상 요소 선택
document.querySelectorAll('.process-step, .skill-category').forEach(el => {
observer.observe(el);
});
});
</script>
<style>
/* --- Hero Section 스타일 수정 --- */
.hero-section {
position: relative;
width: 100%;
height: 500px; /* 요청하신 높이 고정 */
display: flex;
align-items: center;
overflow: hidden;
}
.hero-background {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
z-index: -1;
}
.hero-background .bg-img {
width: 100%;
height: 100%;
object-fit: cover; /* 이미지가 찌그러지지 않고 영역을 꽉 채움 */
}
.hero-overlay {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.6); /* 💡 [수정] 오버레이를 더 어둡게 하여 가독성 향상 */
}
/* Hero Content */
.hero-content {
max-width: 1400px; margin: 0 auto; padding: 0 30px;
width: 100%; display: flex; justify-content: space-between; align-items: center;
position: relative; z-index: 1; color: #fff;
}
.hero-text {
max-width: 45%;
position: absolute;
left: 20.33%;
top: 35.33%;
margin-top: -240px; /* 위로 240px 이동 */
z-index: 2;
color: #fff;
}
.hero-title {
font-size: 3.2rem; font-weight: 800; line-height: 1.2; margin-bottom: 20px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.hero-title .gradient-text {
background: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
text-shadow: none;
}
.hero-subtitle {
font-size: 1.2rem; /* 💡 [수정] 크기 약간 키움 */
opacity: 1;
margin-bottom: 30px;
font-weight: 700; /* 💡 [수정] 굵게 */
line-height: 1.6;
/* 💡 [수정] 흰색 테두리 효과 (그림자) */
text-shadow: 1px 1px 0 #ffffff, -1px -1px 0 #ffffff, 1px -1px 0 #ffffff, -1px 1px 0 #ffffff;
color: #002060; /* 💡 [수정] 진한 남색 */
}
/* 💡 [추가] Hero CTA 버튼 스타일 (최신 트렌드 반영) */
.hero-cta {
margin-top: 40px;
}
.hero-cta .btn-primary {
position: relative;
display: inline-block;
padding: 18px 45px;
font-size: 1.1rem;
font-weight: 700;
color: #fff;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 1px;
/* 배경: 밝은 배경에서도 잘 보이도록 진한 그라데이션 사용 */
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); /* 보라-파랑 그라데이션 */
border-radius: 50px;
box-shadow: 0 10px 20px rgba(37, 117, 252, 0.3); /* 부드러운 그림자 */
transition: all 0.3s ease;
overflow: hidden;
z-index: 1;
border: 1px solid rgba(255,255,255,0.1);
}
/* 호버 시 배경 반전 효과를 위한 가상 요소 */
.hero-cta .btn-primary::before {
content: '';
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background: linear-gradient(135deg, #2575fc 0%, #6a11cb 100%);
z-index: -1;
transition: opacity 0.3s ease;
opacity: 0;
}
.hero-cta .btn-primary:hover {
transform: translateY(-3px); /* 살짝 위로 떠오름 */
box-shadow: 0 15px 30px rgba(37, 117, 252, 0.5); /* 그림자 강조 */
}
.hero-cta .btn-primary:hover::before {
opacity: 1;
}
/* Hero Visual (우측 작은 박스들) */
.creative-showcase {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
.showcase-item {
background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.3);
padding: 20px;
border-radius: 12px;
text-align: center;
transition: transform 0.3s, background 0.3s;
width: 160px;
}
.showcase-item:hover {
transform: translateY(-5px);
background: rgba(0, 0, 0, 0.6);
border-color: #4facfe;
}
.item-icon { font-size: 2rem; margin-bottom: 10px; }
.showcase-item h4 { font-size: 1rem; color: #fff; margin: 0 0 5px; font-weight: 600; }
.item-desc { font-size: 0.75rem; color: #ddd; }
/* --- Portfolio Section (게시판 연동 & 마우스오버) --- */
.portfolio-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 30px;
margin-top: 40px;
}
.portfolio-item { /* 개별 아이템 */ }
.portfolio-wrapper {
position: relative;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
height: 300px;
transform: translateZ(0);
}
.portfolio-image { width: 100%; height: 100%; }
.portfolio-image img {
width: 100%; height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
border-radius: 10px;
}
/* 마우스 오버 효과 핵심 CSS */
.portfolio-overlay {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.85);
display: flex; flex-direction: column;
justify-content: center; align-items: center;
text-align: center;
padding: 30px;
opacity: 0;
transition: opacity 0.3s ease;
border-radius: 10px;
}
.portfolio-wrapper:hover .portfolio-overlay { opacity: 1; }
.portfolio-wrapper:hover .portfolio-image img { transform: scale(1.1); }
.overlay-content h3 { color: #fff; font-size: 1.3rem; margin-bottom: 15px; line-height: 1.4; }
.overlay-content .summary { color: #ccc; font-size: 0.9rem; margin-bottom: 20px; line-height: 1.6; }
.category-tag {
display: inline-block; padding: 4px 10px;
background: #4facfe; color: #fff; border-radius: 20px;
font-size: 0.7rem; margin-bottom: 15px;
}
.btn-view {
display: inline-block; padding: 8px 20px;
border: 1px solid #fff; color: #fff; text-decoration: none;
border-radius: 4px; transition: 0.2s; font-size: 0.9rem;
}
.btn-view:hover { background: #fff; color: #000; }
/* Filter Buttons */
.portfolio-filter { text-align: center; margin-bottom: 30px; }
.filter-btn {
background: #0868cd; /* 💡 [수정] 기본 배경색 진한 파랑 */
border: none; font-size: 1rem; color: #fff; /* 💡 [수정] 기본 글자색 흰색 */
padding: 10px 20px; cursor: pointer; font-weight: 500;
transition: 0.3s;
}
.filter-btn.active, .filter-btn:hover {
background: #4f7595;
color: #fff;
font-weight: 700;
}
/* Process & CTA 스타일 조정 */
.process-step { padding: 20px; }
.step-number {
background: #fff; color: #007bff; border: 2px solid #007bff;
width: 50px; height: 50px; line-height: 46px; border-radius: 50%;
margin: 0 auto 20px; font-weight: bold; font-size: 1.2rem;
}
.cta-section { background: #fff !important; color: #fff; padding: 0px !important; text-align: center; }
.cta-buttons .btn-primary-large { background: #fff; color: #1e3c72; padding: 15px 40px; border-radius: 30px; text-decoration: none; font-weight: bold; margin-right: 15px; }
.cta-section .btn-secondary-large { border: 2px solid #fff !important; background: #1e3c72 !important; color: #fff !important; padding: 15px 40px !important; border-radius: 30px !important; text-decoration: none; font-weight: bold; }
/* 💡 [추가] 플로팅 버튼 스타일 */
.floating-contact-btn {
display: block;
margin-top: 15px;
background-color: #009fe3;
color: #fff;
text-align: center;
padding: 12px 0;
border-radius: 8px;
text-decoration: none;
font-weight: bold;
transition: background-color 0.3s;
}
.floating-contact-btn:hover {
background-color: #007bb5;
}
.floating-contact-btn .icon { margin-right: 5px; }
/* 반응형 */
@media (max-width: 991px) {
.hero-content { flex-direction: column; text-align: center; }
.hero-text { max-width: 100%; margin-bottom: 40px; }
.hero-visual { width: 100%; display: flex; justify-content: center; }
}
</style>