first commit 2
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* rb.board.core.coverage :: list.skin.php
|
||||
* '심층취재' 타입 전용 목록 페이지
|
||||
*/
|
||||
|
||||
// 스킨 CSS 로드
|
||||
$_skin_url = G5_THEME_URL . '/skin/board/rb.board.core.coverage';
|
||||
add_stylesheet('<link rel="stylesheet" href="' . $_skin_url . '/style.css?ver=' . G5_SERVER_TIME . '">', 0);
|
||||
?>
|
||||
<style>
|
||||
/* 게시판 폰트 연동 (설정값이 있을 때만 작동) */
|
||||
<?php if(isset($rb_core['font']) && $rb_core['font']) { ?>
|
||||
.board-container,
|
||||
.board-container * {
|
||||
font-family: 'font-R', '<?php echo $rb_core['font'] ?>', sans-serif !important;
|
||||
}
|
||||
|
||||
/* 강조 텍스트 굵기 보정 */
|
||||
.board-container .card-title,
|
||||
.board-container .list-cell.title,
|
||||
.board-container .btn-primary {
|
||||
font-family: 'font-B', '<?php echo $rb_core['font'] ?>', sans-serif !important;
|
||||
}
|
||||
<?php } ?>
|
||||
</style>
|
||||
|
||||
<?php
|
||||
|
||||
// 💡 [추가] 메인 노출 개수 관련 로직
|
||||
$main_view_max = 'N/A';
|
||||
$main_display_count = 0;
|
||||
|
||||
if ($is_admin) {
|
||||
// 게시판 여분필드(bo_1 ~ bo_10) 중 제목이 'main_view_max'인 필드의 값을 가져옵니다.
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
if (isset($board['bo_'.$i.'_subj']) && $board['bo_'.$i.'_subj'] == 'main_view_max') {
|
||||
$main_view_max = $board['bo_'.$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 현재 메인에 노출된 글의 개수를 카운트합니다.
|
||||
$sql_count = "SELECT COUNT(*) as cnt FROM {$g5['write_prefix']}{$bo_table} WHERE wr_8 = 'Y'";
|
||||
$row_count = sql_fetch($sql_count);
|
||||
$main_display_count = $row_count['cnt'];
|
||||
|
||||
// 최대값이 설정되지 않았거나, 숫자가 아니거나, 비어있으면 '무제한'으로 표시
|
||||
if ($main_view_max === 'N/A' || $main_view_max === '' || !is_numeric($main_view_max)) {
|
||||
$main_view_max = '∞';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 뷰 모드 설정
|
||||
$default_view_mode = isset($board_config['list']['default_view_mode']) ? $board_config['list']['default_view_mode'] : 'card';
|
||||
$view_mode = get_cookie('board_' . $bo_table . '_view_mode') ?: $default_view_mode;
|
||||
|
||||
// 필드 맵 정의
|
||||
$field_map = array(
|
||||
'summary' => 'wr_1',
|
||||
'featured' => 'wr_10',
|
||||
);
|
||||
$ebook_link_field = 'wr_link1';
|
||||
|
||||
// '지정 최신글'과 '일반글'을 분리
|
||||
$featured_list = array();
|
||||
$regular_list = array();
|
||||
foreach ($list as $item) {
|
||||
if ($item[$field_map['featured']] == 'Y') {
|
||||
$featured_list[] = $item;
|
||||
} else {
|
||||
$regular_list[] = $item;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="board-container">
|
||||
|
||||
<!-- 게시판 헤더 -->
|
||||
<div class="board-header">
|
||||
<div class="board-total">
|
||||
Total <span class="text-primary"><?php echo number_format($total_count) ?></span> / <?php echo $page ?> page
|
||||
<?php if ($is_admin): ?>
|
||||
<span class="main-display-count">(메인 노출: <?php echo $main_display_count; ?> / <?php echo $main_view_max; ?>)</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="board-controls">
|
||||
<div class="view-mode-switcher">
|
||||
<button type="button" class="btn-view-mode <?php echo ($view_mode === 'card') ? 'active' : ''; ?>" data-mode="card" title="카드형으로 보기"><i class="fas fa-th-large"></i></button>
|
||||
<button type="button" class="btn-view-mode <?php echo ($view_mode === 'list') ? 'active' : ''; ?>" data-mode="list" title="리스트형으로 보기"><i class="fas fa-bars"></i></button>
|
||||
</div>
|
||||
<div class="board-search">
|
||||
<form name="fsearch" method="get">
|
||||
<input type="hidden" name="bo_table" value="<?php echo $bo_table ?>"><input type="hidden" name="sca" value="<?php echo $sca ?>">
|
||||
<div class="input-group">
|
||||
<select name="sfl" id="sfl"><option value="wr_subject"<?php echo get_selected($sfl, "wr_subject", true); ?>>제목</option><option value="wr_content"<?php echo get_selected($sfl, "wr_content"); ?>>내용</option><option value="wr_subject||wr_content"<?php echo get_selected($sfl, "wr_subject||wr_content"); ?>>제목+내용</option><option value="mb_id,1"<?php echo get_selected($sfl, "mb_id,1"); ?>>회원ID</option><option value="wr_name,1"<?php echo get_selected($sfl, "wr_name,1"); ?>>글쓴이</option></select>
|
||||
<input type="text" name="stx" value="<?php echo stripslashes($stx) ?>" required class="form-control" placeholder="검색어 입력">
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 💡 [핵심] 지정 최신글 출력 영역 (항상 카드형) -->
|
||||
<?php if (!empty($featured_list) && $page === 1): // 첫 페이지에서만 보여줍니다. ?>
|
||||
<div class="featured-list-wrapper">
|
||||
<ul class="card-list">
|
||||
<?php for ($i=0; $i<count($featured_list); $i++) {
|
||||
$item = $featured_list[$i];
|
||||
$thumb = get_list_thumbnail($bo_table, $item['wr_id'], $board['bo_gallery_width'], $board['bo_gallery_height'], false, true);
|
||||
$href = $item[$ebook_link_field] ? $item[$ebook_link_field] : $item['href'];
|
||||
$target = $item[$ebook_link_field] ? '_blank' : '';
|
||||
$summary = cut_str(strip_tags($item[$field_map['summary']] ?: $item['wr_content']), 120);
|
||||
?>
|
||||
<li class="card-item is-featured">
|
||||
<a href="<?php echo $href; ?>" target="<?php echo $target; ?>" class="card-link">
|
||||
<div class="card-thumbnail"><img src="<?php echo $thumb['src']; ?>" alt="<?php echo $thumb['alt']; ?>"><span class="badge-featured"><i class="fa fa-star"></i> E-Book</span></div>
|
||||
<div class="card-content">
|
||||
<?php if ($is_category && $item['ca_name']): ?><span class="card-category"><?php echo $item['ca_name']; ?></span><?php endif; ?>
|
||||
<h3 class="card-title"><?php echo $item['subject']; ?></h3>
|
||||
<p class="card-summary"><?php echo $summary; ?></p>
|
||||
<div class="card-meta"><span class="card-date"><?php echo $item['datetime2']; ?></span></div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="list-separator">
|
||||
<p>최신 6개를 제외하고 나머지는 pdf를 보여주거나 다운후 확인 할 수있습니다.</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<!-- 💡 [핵심 수정] 일반 목록 출력 영역 (카드/리스트 전환) -->
|
||||
<div class="board-list-wrapper" data-view-mode="<?php echo $view_mode; ?>">
|
||||
<?php if (empty($regular_list)): ?>
|
||||
<div class="empty-list">일반 게시물이 없습니다.</div>
|
||||
<?php else: ?>
|
||||
<!-- 카드형 목록 -->
|
||||
<div class="card-list-view">
|
||||
<ul class="card-list">
|
||||
<?php for ($i=0; $i<count($regular_list); $i++) {
|
||||
$item = $regular_list[$i];
|
||||
$thumb = get_list_thumbnail($bo_table, $item['wr_id'], $board['bo_gallery_width'], $board['bo_gallery_height'], false, true);
|
||||
$href = $item['href'];
|
||||
$summary = cut_str(strip_tags($item[$field_map['summary']] ?: $item['wr_content']), 120);
|
||||
?>
|
||||
<li class="card-item">
|
||||
<a href="<?php echo $href; ?>" class="card-link">
|
||||
<div class="card-thumbnail"><img src="<?php echo $thumb['src']; ?>" alt="<?php echo $thumb['alt']; ?>"></div>
|
||||
<div class="card-content">
|
||||
<?php if ($is_category && $item['ca_name']): ?><span class="card-category"><?php echo $item['ca_name']; ?></span><?php endif; ?>
|
||||
<h3 class="card-title"><?php echo $item['subject']; ?></h3>
|
||||
<p class="card-summary"><?php echo $summary; ?></p>
|
||||
<div class="card-meta"><span class="card-date"><?php echo $item['datetime2']; ?></span></div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 리스트형 목록 -->
|
||||
<div class="list-view">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-header">
|
||||
<div class="list-cell num">번호</div><div class="list-cell title">제목</div><div class="list-cell name">글쓴이</div><div class="list-cell date">날짜</div><div class="list-cell hit">조회</div>
|
||||
</li>
|
||||
<?php for ($i=0; $i<count($regular_list); $i++) {
|
||||
$item = $regular_list[$i];
|
||||
?>
|
||||
<li class="list-group-item">
|
||||
<div class="list-cell num"><?php echo $item['num']; ?></div>
|
||||
<div class="list-cell title">
|
||||
<a href="<?php echo $item['href']; ?>">
|
||||
<?php echo $item['subject']; ?>
|
||||
<?php if ($item['icon_new']) echo ' <span class="icon-new">N</span>'; ?>
|
||||
</a>
|
||||
</div>
|
||||
<div class="list-cell name"><?php echo $item['name']; ?></div>
|
||||
<div class="list-cell date"><?php echo $item['datetime2']; ?></div>
|
||||
<div class="list-cell hit"><?php echo $item['wr_hit']; ?></div>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.main-display-count {
|
||||
margin-left: 10px;
|
||||
font-size: 0.9em;
|
||||
color: #777;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,234 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/**
|
||||
* coverage :: style.css
|
||||
* 💡 [수정] 고유 ID 선택자를 #coverage-board로 변경합니다.
|
||||
*/
|
||||
|
||||
/* ==========================================================================
|
||||
Board Common Styles
|
||||
========================================================================== */
|
||||
#coverage-board .board-container,
|
||||
#coverage-board .board-write-container,
|
||||
#coverage-board .board-view-container {
|
||||
background-color: #fff;
|
||||
padding: 40px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.08);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 이하 모든 #coverage-board 선택자를 #coverage-board로 변경 */
|
||||
|
||||
#coverage-board .board-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 20px;
|
||||
padding-bottom: 25px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
#coverage-board .board-total { font-size: 1.2rem; color: #555; font-weight: 500; text-align: left; }
|
||||
#coverage-board .board-total .text-primary { color: #0056b3; font-weight: 700; }
|
||||
#coverage-board .board-controls { display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
|
||||
#coverage-board .view-mode-switcher { display: flex; border: 1px solid #ddd; border-radius: 8px; overflow: hidden; }
|
||||
#coverage-board .btn-view-mode { background: #fff; border: none; padding: 10px 15px; cursor: pointer; color: #888; font-size: 1.2rem; line-height: 1; transition: all 0.2s ease; }
|
||||
#coverage-board .btn-view-mode.active { background: #0056b3; color: #fff; }
|
||||
#coverage-board .btn-view-mode:hover:not(.active) { background: #f0f0f0; color: #333; }
|
||||
#coverage-board .board-search { flex-grow: 1; }
|
||||
#coverage-board .board-search .input-group { display: flex; align-items: center; width: 100%; max-width: 400px; margin-left: auto; }
|
||||
#coverage-board .board-search select,
|
||||
#coverage-board .board-search input[type="text"] { border: 1px solid #ddd; padding: 0 15px; height: 42px; font-size: 1rem; background: #fff; border-radius: 8px; transition: border-color 0.2s ease; }
|
||||
#coverage-board .board-search select { border-radius: 8px 0 0 8px; border-right: none; }
|
||||
#coverage-board .board-search input[type="text"]:focus { border-color: #0056b3; outline: none; box-shadow: 0 0 0 2px rgba(0, 86, 179, 0.2); }
|
||||
#coverage-board .board-search .btn { border-radius: 0 8px 8px 0; height: 42px; padding: 0 20px; background: #0056b3; color: #fff; border: none; transition: background-color 0.2s ease; }
|
||||
#coverage-board .board-search .btn:hover { background-color: #003d82; }
|
||||
|
||||
#coverage-board .list-separator { text-align: center; padding: 40px 20px; margin: 40px 0; border-top: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0; background-color: #f9f9f9; }
|
||||
#coverage-board .list-separator p { font-size: 1.1rem; color: #666; font-weight: 500; }
|
||||
|
||||
/* 💡 [최종 수정] 뷰 전환이 올바르게 동작하도록 선택자를 .board-list-wrapper 로 수정합니다. */
|
||||
#coverage-board .board-list-wrapper[data-view-mode="card"] .card-list-view { display: block; }
|
||||
#coverage-board .board-list-wrapper[data-view-mode="list"] .list-view { display: block; }
|
||||
#coverage-board .board-list-wrapper .card-list-view,
|
||||
#coverage-board .board-list-wrapper .list-view { display: none; }
|
||||
|
||||
#coverage-board .empty-list { padding: 100px 20px; text-align: center; color: #888; font-size: 1.6rem; font-weight: 600; }
|
||||
#coverage-board .card-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 30px; }
|
||||
#coverage-board .card-item { background: #fff; border-radius: 12px; overflow: hidden; box-shadow: 0 8px 25px rgba(0,0,0,0.08); transition: transform 0.3s ease, box-shadow 0.3s ease; border: none; }
|
||||
#coverage-board .card-item:hover { transform: translateY(-7px); box-shadow: 0 12px 35px rgba(0,0,0,0.15); }
|
||||
#coverage-board .card-link { display: block; text-decoration: none; color: inherit; }
|
||||
#coverage-board .card-thumbnail { position: relative; width: 100%; padding-top: 70%; background-color: #f0f0f0; }
|
||||
#coverage-board .card-thumbnail img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; }
|
||||
#coverage-board .badge-pdf, #coverage-board .badge-link, #coverage-board .badge-featured { position: absolute; top: 15px; right: 15px; padding: 8px 15px; border-radius: 20px; font-size: 0.85rem; font-weight: 700; color: #fff; text-transform: uppercase; letter-spacing: 0.5px; }
|
||||
#coverage-board .badge-pdf { background-color: #e74c3c; }
|
||||
#coverage-board .badge-link { background-color: #3498db; }
|
||||
#coverage-board .badge-featured { background-color: #9b59b6; }
|
||||
#coverage-board .card-content { padding: 25px; }
|
||||
#coverage-board .card-category { display: inline-block; font-size: 0.9rem; font-weight: 700; color: #0056b3; margin-bottom: 10px; }
|
||||
#coverage-board .card-title { font-size: 1.5rem; font-weight: 800; margin: 0 0 15px 0; line-height: 1.4; min-height: 2.8em; color: #222; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
|
||||
#coverage-board .card-summary { font-size: 1rem; color: #666; line-height: 1.7; height: 5.1em; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
|
||||
#coverage-board .card-meta { margin-top: 20px; padding-top: 15px; border-top: 1px solid #f0f0f0; font-size: 0.9rem; color: #888; }
|
||||
#coverage-board .card-item.is-featured { border: 2px solid #9b59b6; box-shadow: 0 8px 25px rgba(155, 89, 182, 0.2); }
|
||||
#coverage-board .list-group { border-top: 2px solid #333; }
|
||||
#coverage-board .list-group-header, #coverage-board .list-group-item { display: flex; align-items: center; padding: 18px 10px; border-bottom: 1px solid #f0f0f0; }
|
||||
#coverage-board .list-group-header { font-weight: 700; background-color: #f9f9f9; font-size: 1.05rem; }
|
||||
#coverage-board .list-group-item:hover { background-color: #f5f5f5; }
|
||||
#coverage-board .list-cell { padding: 0 10px; text-align: center; color: #555; }
|
||||
#coverage-board .list-cell.num { flex: 0 0 80px; }
|
||||
#coverage-board .list-cell.title { flex: 1; text-align: left; }
|
||||
#coverage-board .list-cell.title a { color: #333; text-decoration: none; font-weight: 500; }
|
||||
#coverage-board .list-group-item.is-featured { background-color: #fdf8ff; }
|
||||
#coverage-board .badge-featured-list { color: #9b59b6; margin-right: 8px; }
|
||||
|
||||
#coverage-board .view-header { padding-bottom: 20px; border-bottom: 1px solid #e0e0e0; margin-bottom: 30px; }
|
||||
#coverage-board .view-header h1 { font-size: 2.5rem; font-weight: 800; margin-bottom: 15px; line-height: 1.3; }
|
||||
#coverage-board .view-meta { display: flex; flex-wrap: wrap; gap: 10px 20px; color: #888; font-size: 0.95rem; }
|
||||
#coverage-board .view-meta .meta-item i { margin-right: 5px; color: #aaa; }
|
||||
#coverage-board .view-content { padding: 30px 0; }
|
||||
#coverage-board .view-body-images { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 25px; margin-top: 40px; padding-top: 30px; border-top: 1px solid #eee; justify-items: center; }
|
||||
#coverage-board .view-body-images .body-image-item { max-width: 100%; text-align: center; background-color: #fcfcfc; border-radius: 10px; overflow: hidden; box-shadow: 0 5px 20px rgba(0,0,0,0.08); transition: transform 0.2s ease; }
|
||||
#coverage-board .view-body-images .body-image-item:hover { transform: translateY(-5px); }
|
||||
#coverage-board .view-body-images .body-image-item img { max-width: 100%; height: auto; display: block; margin: 0 auto; object-fit: contain; border-bottom: 1px solid #eee; }
|
||||
#coverage-board .view-body-images .body-image-item figcaption { padding: 15px; font-size: 0.9rem; color: #666; line-height: 1.5; }
|
||||
|
||||
/* ==========================================================================
|
||||
View Detail Content Styles (본문 스타일)
|
||||
========================================================================== */
|
||||
#coverage-board .view-detail-content {
|
||||
margin-top: 40px;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.8; /* 전체적인 줄 높이 */
|
||||
color: #333;
|
||||
white-space: normal; /* 💡 [수정] 소스 코드 줄바꿈이 공백으로 표시되지 않도록 normal로 변경 */
|
||||
word-break: break-word;
|
||||
}
|
||||
#coverage-board .view-detail-content * {
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
/* 💡 [추가] 에디터가 삽입하는 인라인 스타일의 line-height를 재정의 */
|
||||
line-height: inherit !important;
|
||||
}
|
||||
#coverage-board .view-detail-content p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px; /* 💡 [수정] 문단 간격 (news4j와 유사하게) */
|
||||
line-height: 1.7; /* 💡 [수정] 문단 내 줄 높이 */
|
||||
}
|
||||
/* 💡 [추가] 빈 p 태그의 높이를 없애 불필요한 공백 제거 */
|
||||
#coverage-board .view-detail-content p:empty {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
#coverage-board .view-detail-content p:empty::before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#coverage-board .view-detail-content h1,
|
||||
#coverage-board .view-detail-content h2,
|
||||
#coverage-board .view-detail-content h3,
|
||||
#coverage-board .view-detail-content h4,
|
||||
#coverage-board .view-detail-content h5,
|
||||
#coverage-board .view-detail-content h6 {
|
||||
margin-top: 30px; /* 💡 [수정] 제목 위 간격 */
|
||||
margin-bottom: 15px; /* 💡 [수정] 제목 아래 간격 */
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
color: #222;
|
||||
}
|
||||
#coverage-board .view-detail-content h1 { font-size: 2.2rem; } /* 💡 [수정] news4j와 유사하게 조정 */
|
||||
#coverage-board .view-detail-content h2 { font-size: 2rem; }
|
||||
#coverage-board .view-detail-content h3 { font-size: 1.7rem; }
|
||||
#coverage-board .view-detail-content h4 { font-size: 1.4rem; }
|
||||
|
||||
/* 💡 [추가] 블록 요소 바로 뒤에 오는 불필요한 br 태그 숨김 (에디터가 삽입하는 경우) */
|
||||
#coverage-board .view-detail-content p + br,
|
||||
#coverage-board .view-detail-content h1 + br,
|
||||
#coverage-board .view-detail-content h2 + br,
|
||||
#coverage-board .view-detail-content h3 + br,
|
||||
#coverage-board .view-detail-content div + br {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#coverage-board .view-detail-content ul, #coverage-board .view-detail-content ol { margin-left: 20px; margin-bottom: 1.5em; }
|
||||
#coverage-board .view-detail-content ul li { list-style: disc; margin-bottom: 0.5em; }
|
||||
#coverage-board .view-detail-content ol li { list-style: decimal; margin-bottom: 0.5em; }
|
||||
#coverage-board .view-detail-content blockquote { border-left: 4px solid #0056b3; padding: 10px 20px; margin: 1.5em 0; background-color: #f8f8f8; color: #555; font-style: italic; }
|
||||
|
||||
#coverage-board .download-box { margin-top: 30px; padding-top: 30px; border-top: 1px solid #eee; }
|
||||
#coverage-board .download-box h3 { font-size: 1.3rem; font-weight: 700; margin-bottom: 15px; color: #333; }
|
||||
#coverage-board .download-list { list-style: none; padding: 0; margin: 0; border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; }
|
||||
#coverage-board .download-list li { border-bottom: 1px solid #e0e0e0; }
|
||||
#coverage-board .download-list li:last-child { border-bottom: none; }
|
||||
#coverage-board .download-list a { display: flex; align-items: center; padding: 15px 20px; text-decoration: none; color: #555; transition: background-color 0.2s ease; }
|
||||
#coverage-board .download-list a:hover { background-color: #f9f9f9; }
|
||||
#coverage-board .download-list .file-icon { font-size: 1.5rem; color: #888; margin-right: 15px; width: 25px; text-align: center; }
|
||||
#coverage-board .download-list .fa-file-pdf-o { color: #e74c3c; }
|
||||
#coverage-board .download-list .fa-file-image-o { color: #3498db; }
|
||||
#coverage-board .download-list .fa-file-archive-o { color: #f39c12; }
|
||||
#coverage-board .download-list .file-name { flex-grow: 1; font-weight: 500; }
|
||||
#coverage-board .download-list .file-size { font-size: 0.9rem; color: #888; }
|
||||
#coverage-board .view-footer { margin-top: 40px; padding-top: 30px; border-top: 1px solid #e0e0e0; display: flex; justify-content: space-between; align-items: center; }
|
||||
#coverage-board .btn-group-left, #coverage-board .btn-group-right { display: flex; gap: 10px; }
|
||||
|
||||
#coverage-board .board-footer { margin-top: 40px; display: flex; justify-content: space-between; align-items: center; }
|
||||
#coverage-board .pagination-wrapper, #coverage-board .load-more-wrapper { flex-grow: 1; text-align: center; }
|
||||
#coverage-board .board-footer .btn-group { display: flex; gap: 10px; margin-left: auto; }
|
||||
#coverage-board .board-footer .btn, #coverage-board .view-footer .btn { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; border-radius: 8px; font-size: 1.1rem; text-align: center; font-weight: 700; transition: all 0.2s ease; border: none; }
|
||||
#coverage-board .board-footer .btn:hover, #coverage-board .view-footer .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
|
||||
#coverage-board .board-footer .btn-secondary, #coverage-board .view-footer .btn-secondary { background-color: #6c757d; color: #fff; }
|
||||
#coverage-board .board-footer .btn-primary, #coverage-board .view-footer .btn-primary { background-color: #0056b3; color: #fff; }
|
||||
|
||||
#coverage-board .write-form-group { margin-bottom: 25px; }
|
||||
#coverage-board .form-divider { margin: 40px 0; border: 0; border-top: 1px solid #e0e0e0; }
|
||||
#coverage-board .admin-options-group { background-color: #fcfcfc; padding: 25px; border-radius: 8px; margin-top: 30px; border: 1px solid #e0e0e0; }
|
||||
#coverage-board .form-section-title { font-size: 1.3rem; font-weight: 700; margin: 0 0 20px 0; color: #333; }
|
||||
/*#coverage-board .form-check-label { display: flex; align-items: center; gap: 10px; font-size: 1.1rem; cursor: pointer; }*/
|
||||
/*#coverage-board .form-check-label input[type="checkbox"] { -webkit-appearance: checkbox; -moz-appearance: checkbox; appearance: checkbox; width: 18px; height: 18px; opacity: 1; position: static; }*/
|
||||
#coverage-board .write-form-footer { margin-top: 40px; display: flex; justify-content: flex-end; gap: 10px; }
|
||||
#coverage-board .write-form-footer .btn { text-decoration: none; border-radius: 8px; font-size: 1.1rem; font-weight: 700; border: none; transition: all 0.2s ease; }
|
||||
#coverage-board .write-form-footer .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
|
||||
#coverage-board .write-form-footer .btn-secondary { background-color: #6c757d; color: #fff; }
|
||||
#coverage-board .write-form-footer .btn-primary { background-color: #0056b3; color: #fff; }
|
||||
|
||||
/* 3-Column Layout - PC 전용 */
|
||||
#coverage-board .three-column-layout { display: flex; gap: 30px; }
|
||||
#coverage-board .layout-sidebar-left, #coverage-board .layout-sidebar-right { flex: 0 0 240px; position: sticky; top: 100px; align-self: flex-start; }
|
||||
#coverage-board .layout-main-content { flex: 1; min-width: 0; }
|
||||
.sub-page-container {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
.layout-main-content {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
/* 💡 [추가] 관리자 옵션 체크박스 스타일 */
|
||||
#coverage-board .admin-option-item {
|
||||
background: #f9f9f9;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
#coverage-board .admin-option-checkbox {
|
||||
appearance: checkbox !important;
|
||||
-webkit-appearance: checkbox !important;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
cursor: pointer !important;
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
display: inline-block !important;
|
||||
position: static !important;
|
||||
margin-right: 10px !important;
|
||||
}
|
||||
#coverage-board .admin-option-item .option-text {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* rb.board.core.coverage :: view.skin.php
|
||||
* '심층취재' 타입 전용 뷰어 - 본문/이미지 출력 및 콘텐츠 타입에 따른 렌더링 담당
|
||||
*/
|
||||
|
||||
// 스킨 CSS 로드
|
||||
$_skin_url = G5_THEME_URL . '/skin/board/rb.board.core.coverage';
|
||||
add_stylesheet('<link rel="stylesheet" href="' . $_skin_url . '/style.css?ver=' . G5_SERVER_TIME . '">', 0);
|
||||
|
||||
if (!function_exists('get_extension')) {
|
||||
function get_extension($filename) {
|
||||
$filename = basename($filename);
|
||||
return substr(strrchr($filename, "."), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 💡 [핵심] 첨부파일 재구성: 썸네일(첫번째 파일)을 제외하고, 본문 이미지를 구성합니다.
|
||||
$body_images = array();
|
||||
|
||||
if ($view['file']['count'] > 1) { // 썸네일(첫번째 파일)을 제외하고 2번째 파일부터 처리
|
||||
$temp_files = $view['file'];
|
||||
unset($temp_files['count']);
|
||||
|
||||
for ($i = 1; $i < $view['file']['count']; $i++) {
|
||||
if (!isset($temp_files[$i])) continue;
|
||||
$file = $temp_files[$i];
|
||||
$ext = strtolower(get_extension($file['source']));
|
||||
|
||||
// 이미지 파일이면 본문 이미지 배열에 추가
|
||||
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
|
||||
$body_images[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="coverage-board">
|
||||
<!-- 💡 [추가] 관리자용 메인 노출 상태 표시 -->
|
||||
<?php if ($is_admin && $view['wr_8'] == 'Y'): ?>
|
||||
<div class="admin-option-item">
|
||||
<span class="option-text">💡 이 글은 메인 화면 포트폴리오 영역에 노출되고 있습니다.</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 💡 [핵심] 본문 내용을 콘텐츠 타입에 따라 올바르게 출력합니다. -->
|
||||
<div class="view-detail-content">
|
||||
<?php
|
||||
// 💡 [추가] 본문 내의 인라인 폰트 설정을 강제로 제거하는 함수
|
||||
if (!function_exists('clean_font_styles')) {
|
||||
function clean_font_styles($content) {
|
||||
// style 속성 내의 font-family 항목을 제거 (정규식 사용)
|
||||
return preg_replace('/font-family\s*:\s*[^;"]+;?/i', '', $content);
|
||||
}
|
||||
}
|
||||
|
||||
// HTML 에디터 사용 여부에 따라 conv_content 처리
|
||||
$html = 0; // 기본값은 일반 텍스트
|
||||
if (strstr($view['wr_option'], 'html1')) {
|
||||
$html = 1;
|
||||
} else if (strstr($view['wr_option'], 'html2')) {
|
||||
$html = 2;
|
||||
}
|
||||
|
||||
// 💡 [수정] HTML 태그가 포함되어 있으면 강제로 HTML 모드로 처리
|
||||
if ($html == 0 && preg_match('/<[a-z][\s\S]*>/i', $view['wr_content'])) {
|
||||
$html = 2; // HTML 태그가 발견되면 강제로 HTML2 모드 (모든 HTML 허용)
|
||||
}
|
||||
|
||||
if ($html > 0) {
|
||||
// 💡 [핵심] HTML 모드일 때는 원본 내용을 그대로 출력
|
||||
// 이미지 경로 보정과 인라인 폰트 제거를 함께 적용합니다.
|
||||
$processed_content = g5_dynamic_img_url($view['wr_content']);
|
||||
echo clean_font_styles($processed_content);
|
||||
} else {
|
||||
// 일반 텍스트 모드일 때는 기존처럼 처리
|
||||
echo nl2br(get_text($view['wr_content']));
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($body_images)): ?>
|
||||
<div class="view-body-images">
|
||||
<?php foreach ($body_images as $image): ?>
|
||||
<figure class="body-image-item">
|
||||
<img src="<?php echo $image['path'].'/'.$image['file']; ?>" alt="<?php echo $image['source']; ?>" data-full-src="<?php echo $image['path'].'/'.$image['file']; ?>">
|
||||
<figcaption><?php echo $image['content']; ?></figcaption>
|
||||
</figure>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="view-footer">
|
||||
<div class="btn-group-left">
|
||||
<?php if ($prev_href): ?><a href="<?php echo $prev_href ?>" class="btn btn-secondary">이전글</a><?php endif; ?>
|
||||
<?php if ($next_href): ?><a href="<?php echo $next_href ?>" class="btn btn-secondary">다음글</a><?php endif; ?>
|
||||
</div>
|
||||
<div class="btn-group-right">
|
||||
<a href="<?php echo $list_href ?>" class="btn btn-primary">목록</a>
|
||||
<?php if ($update_href): ?><a href="<?php echo $update_href ?>" class="btn btn-secondary">수정</a><?php endif; ?>
|
||||
<?php if ($delete_href): ?><a href="<?php echo $delete_href ?>" onclick="del(this.href); return false;" class="btn btn-secondary">삭제</a><?php endif; ?>
|
||||
<?php if ($write_href): ?><a href="<?php echo $write_href ?>" class="btn btn-primary">글쓰기</a><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 💡 [추가] 이미지 라이트박스 HTML 구조 -->
|
||||
<div id="image-lightbox-popup" class="image-lightbox-popup">
|
||||
<span class="lightbox-close-btn">×</span>
|
||||
<img class="lightbox-content-img" id="lightbox-img-element">
|
||||
<div class="lightbox-caption" id="lightbox-caption-element"></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 💡 [추가] 이미지 라이트박스 CSS */
|
||||
.image-lightbox-popup {
|
||||
display: none; /* 기본적으로 숨김 */
|
||||
position: fixed; /* 화면 전체를 덮음 */
|
||||
z-index: 10000; /* 다른 요소 위에 표시 */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto; /* 이미지가 화면보다 클 경우 스크롤 */
|
||||
background-color: rgba(0, 0, 0, 0.9); /* 반투명 검정 배경 */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.lightbox-content-img {
|
||||
margin: auto;
|
||||
display: block;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
object-fit: contain; /* 이미지 비율 유지하며 컨테이너에 맞춤 */
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.lightbox-caption {
|
||||
color: #ccc;
|
||||
font-size: 1.2rem;
|
||||
padding: 15px 20px;
|
||||
text-align: center;
|
||||
max-width: 90%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.lightbox-close-btn {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 35px;
|
||||
color: #fff;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.lightbox-close-btn:hover,
|
||||
.lightbox-close-btn:focus {
|
||||
color: #bbb;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 모바일 반응형 */
|
||||
@media only screen and (max-width: 768px) {
|
||||
.lightbox-content-img {
|
||||
max-width: 95%;
|
||||
max-height: 85%;
|
||||
}
|
||||
.lightbox-close-btn {
|
||||
font-size: 30px;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
}
|
||||
.lightbox-caption {
|
||||
font-size: 1rem;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const lightbox = document.getElementById('image-lightbox-popup');
|
||||
const lightboxImg = document.getElementById('lightbox-img-element');
|
||||
const lightboxCaption = document.getElementById('lightbox-caption-element');
|
||||
const closeBtn = document.querySelector('.lightbox-close-btn');
|
||||
const bodyImagesContainer = document.querySelector('.view-body-images');
|
||||
|
||||
if (bodyImagesContainer) {
|
||||
bodyImagesContainer.addEventListener('click', function(e) {
|
||||
if (e.target.tagName === 'IMG') {
|
||||
const imgSrc = e.target.getAttribute('data-full-src') || e.target.src;
|
||||
const imgAlt = e.target.alt;
|
||||
|
||||
lightbox.style.display = 'flex';
|
||||
lightboxImg.src = imgSrc;
|
||||
lightboxCaption.textContent = imgAlt;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 닫기 버튼 클릭 시 라이트박스 닫기
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', function() {
|
||||
lightbox.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// 라이트박스 배경 클릭 시 닫기 (이미지 클릭은 제외)
|
||||
if (lightbox) {
|
||||
lightbox.addEventListener('click', function(e) {
|
||||
if (e.target === lightbox) {
|
||||
lightbox.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ESC 키 눌렀을 때 라이트박스 닫기
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && lightbox.style.display === 'flex') {
|
||||
lightbox.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* rb.board.core.coverage :: view.skin.php
|
||||
* '심층취재' 타입 전용 뷰어 - 본문/이미지 출력 및 콘텐츠 타입에 따른 렌더링 담당
|
||||
*/
|
||||
|
||||
if (!function_exists('get_extension')) {
|
||||
function get_extension($filename) {
|
||||
$filename = basename($filename);
|
||||
return substr(strrchr($filename, "."), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 💡 [핵심] 첨부파일 재구성: 썸네일(첫번째 파일)을 제외하고, 본문 이미지를 구성합니다.
|
||||
$body_images = array();
|
||||
|
||||
if ($view['file']['count'] > 1) { // 썸네일(첫번째 파일)을 제외하고 2번째 파일부터 처리
|
||||
$temp_files = $view['file'];
|
||||
unset($temp_files['count']);
|
||||
|
||||
for ($i = 1; $i < $view['file']['count']; $i++) {
|
||||
if (!isset($temp_files[$i])) continue;
|
||||
$file = $temp_files[$i];
|
||||
$ext = strtolower(get_extension($file['source']));
|
||||
|
||||
// 이미지 파일이면 본문 이미지 배열에 추가
|
||||
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
|
||||
$body_images[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="coverage-board">
|
||||
<!-- 💡 [추가] 관리자용 메인 노출 상태 표시 -->
|
||||
<?php if ($is_admin && $view['wr_8'] == 'Y'): ?>
|
||||
<div class="admin-option-item">
|
||||
<span class="option-text">💡 이 글은 메인 화면 포트폴리오 영역에 노출되고 있습니다.</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 💡 [핵심] 본문 내용을 콘텐츠 타입에 따라 올바르게 출력합니다. -->
|
||||
<div class="view-detail-content">
|
||||
<?php
|
||||
// HTML 에디터 사용 여부에 따라 conv_content 처리
|
||||
$html = 1;
|
||||
if (strstr($view['wr_option'], 'html1')) {
|
||||
$html = 1;
|
||||
} else if (strstr($view['wr_option'], 'html2')) {
|
||||
$html = 2;
|
||||
}
|
||||
// 💡 [최종 수정] HTML 에디터로 작성된 경우 conv_content로 HTML 렌더링, 아니면 줄바꿈 유지 텍스트
|
||||
if ($html > 0) {
|
||||
// 💡 [핵심] g5_dynamic_img_url 함수를 적용하여 이미지 경로를 동적으로 변경합니다.
|
||||
echo g5_dynamic_img_url(conv_content($view['wr_content'], $html,false));
|
||||
} else {
|
||||
echo nl2br(get_text($view['wr_content']));
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($body_images)): ?>
|
||||
<div class="view-body-images">
|
||||
<?php foreach ($body_images as $image): ?>
|
||||
<figure class="body-image-item">
|
||||
<img src="<?php echo $image['path'].'/'.$image['file']; ?>" alt="<?php echo $image['source']; ?>">
|
||||
<figcaption><?php echo $image['content']; ?></figcaption>
|
||||
</figure>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="view-footer">
|
||||
<div class="btn-group-left">
|
||||
<?php if ($prev_href): ?><a href="<?php echo $prev_href ?>" class="btn btn-secondary">이전글</a><?php endif; ?>
|
||||
<?php if ($next_href): ?><a href="<?php echo $next_href ?>" class="btn btn-secondary">다음글</a><?php endif; ?>
|
||||
</div>
|
||||
<div class="btn-group-right">
|
||||
<a href="<?php echo $list_href ?>" class="btn btn-primary">목록</a>
|
||||
<?php if ($update_href): ?><a href="<?php echo $update_href ?>" class="btn btn-secondary">수정</a><?php endif; ?>
|
||||
<?php if ($delete_href): ?><a href="<?php echo $delete_href ?>" onclick="del(this.href); return false;" class="btn btn-secondary">삭제</a><?php endif; ?>
|
||||
<?php if ($write_href): ?><a href="<?php echo $write_href ?>" class="btn btn-primary">글쓰기</a><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* rb.board.core.coverage :: view.skin.php
|
||||
* '심층취재' 타입 전용 뷰어 - 본문/이미지 출력 및 콘텐츠 타입에 따른 렌더링 담당
|
||||
*/
|
||||
|
||||
if (!function_exists('get_extension')) {
|
||||
function get_extension($filename) {
|
||||
$filename = basename($filename);
|
||||
return substr(strrchr($filename, "."), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 💡 [핵심] 첨부파일 재구성: 썸네일(첫번째 파일)을 제외하고, 본문 이미지를 구성합니다.
|
||||
$body_images = array();
|
||||
|
||||
if ($view['file']['count'] > 1) { // 썸네일(첫번째 파일)을 제외하고 2번째 파일부터 처리
|
||||
$temp_files = $view['file'];
|
||||
unset($temp_files['count']);
|
||||
|
||||
for ($i = 1; $i < $view['file']['count']; $i++) {
|
||||
if (!isset($temp_files[$i])) continue;
|
||||
$file = $temp_files[$i];
|
||||
$ext = strtolower(get_extension($file['source']));
|
||||
|
||||
// 이미지 파일이면 본문 이미지 배열에 추가
|
||||
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
|
||||
$body_images[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<style>
|
||||
.view-detail-content {
|
||||
white-space: pre-wrap; /* 줄바꿈과 공백을 유지하고, 필요한 경우 줄바꿈 */
|
||||
word-break: break-word; /* 긴 단어가 있을 경우 줄바꿈 */
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="coverage-board">
|
||||
<!-- 💡 [추가] 관리자용 메인 노출 상태 표시 -->
|
||||
<?php if ($is_admin && $view['wr_8'] == 'Y'): ?>
|
||||
<div class="admin-option-item">
|
||||
<span class="option-text">💡 이 글은 메인 화면 포트폴리오 영역에 노출되고 있습니다.</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 💡 [핵심] 본문 내용을 콘텐츠 타입에 따라 올바르게 출력합니다. -->
|
||||
<div class="view-detail-content">
|
||||
<?php
|
||||
// HTML 에디터 사용 여부에 따라 conv_content 처리
|
||||
$html = 0; // 기본값은 일반 텍스트
|
||||
if (strstr($view['wr_option'], 'html1')) {
|
||||
$html = 1;
|
||||
} else if (strstr($view['wr_option'], 'html2')) {
|
||||
$html = 2;
|
||||
}
|
||||
|
||||
// 💡 [수정] HTML 태그가 포함되어 있으면 강제로 HTML 모드로 처리
|
||||
// 이 로직은 wr_option이 잘못 설정된 경우에도 HTML을 렌더링하도록 합니다.
|
||||
// XSS 취약점에 주의해야 합니다.
|
||||
if ($html == 0 && preg_match('/<[a-z][\s\S]*>/i', $view['wr_content'])) {
|
||||
$html = 2; // HTML 태그가 발견되면 강제로 HTML2 모드 (모든 HTML 허용)
|
||||
}
|
||||
|
||||
if ($html > 0) {
|
||||
// 💡 [핵심] g5_dynamic_img_url 함수를 적용하여 이미지 경로를 동적으로 변경합니다.
|
||||
echo g5_dynamic_img_url(conv_content($view['wr_content'], $html));
|
||||
} else {
|
||||
echo nl2br(get_text($view['wr_content']));
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($body_images)): ?>
|
||||
<div class="view-body-images">
|
||||
<?php foreach ($body_images as $image): ?>
|
||||
<figure class="body-image-item">
|
||||
<img src="<?php echo $image['path'].'/'.$image['file']; ?>" alt="<?php echo $image['source']; ?>">
|
||||
<figcaption><?php echo $image['content']; ?></figcaption>
|
||||
</figure>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="view-footer">
|
||||
<div class="btn-group-left">
|
||||
<?php if ($prev_href): ?><a href="<?php echo $prev_href ?>" class="btn btn-secondary">이전글</a><?php endif; ?>
|
||||
<?php if ($next_href): ?><a href="<?php echo $next_href ?>" class="btn btn-secondary">다음글</a><?php endif; ?>
|
||||
</div>
|
||||
<div class="btn-group-right">
|
||||
<a href="<?php echo $list_href ?>" class="btn btn-primary">목록</a>
|
||||
<?php if ($update_href): ?><a href="<?php echo $update_href ?>" class="btn btn-secondary">수정</a><?php endif; ?>
|
||||
<?php if ($delete_href): ?><a href="<?php echo $delete_href ?>" onclick="del(this.href); return false;" class="btn btn-secondary">삭제</a><?php endif; ?>
|
||||
<?php if ($write_href): ?><a href="<?php echo $write_href ?>" class="btn btn-primary">글쓰기</a><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* rb.board.core.coverage :: view.skin.php
|
||||
* '심층취재' 타입 전용 뷰어 - 본문/이미지 출력 및 콘텐츠 타입에 따른 렌더링 담당
|
||||
*/
|
||||
|
||||
if (!function_exists('get_extension')) {
|
||||
function get_extension($filename) {
|
||||
$filename = basename($filename);
|
||||
return substr(strrchr($filename, "."), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 💡 [핵심] 첨부파일 재구성: 썸네일(첫번째 파일)을 제외하고, 본문 이미지를 구성합니다.
|
||||
$body_images = array();
|
||||
|
||||
if ($view['file']['count'] > 1) { // 썸네일(첫번째 파일)을 제외하고 2번째 파일부터 처리
|
||||
$temp_files = $view['file'];
|
||||
unset($temp_files['count']);
|
||||
|
||||
for ($i = 1; $i < $view['file']['count']; $i++) {
|
||||
if (!isset($temp_files[$i])) continue;
|
||||
$file = $temp_files[$i];
|
||||
$ext = strtolower(get_extension($file['source']));
|
||||
|
||||
// 이미지 파일이면 본문 이미지 배열에 추가
|
||||
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
|
||||
$body_images[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="coverage-board">
|
||||
<!-- 💡 [추가] 관리자용 메인 노출 상태 표시 -->
|
||||
<?php if ($is_admin && $view['wr_8'] == 'Y'): ?>
|
||||
<div class="admin-option-item">
|
||||
<span class="option-text">💡 이 글은 메인 화면 포트폴리오 영역에 노출되고 있습니다.</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 💡 [핵심] 본문 내용을 콘텐츠 타입에 따라 올바르게 출력합니다. -->
|
||||
<div class="view-detail-content">
|
||||
<?php
|
||||
// HTML 에디터 사용 여부에 따라 conv_content 처리
|
||||
$html = 0; // 기본값은 일반 텍스트
|
||||
if (strstr($view['wr_option'], 'html1')) {
|
||||
$html = 1;
|
||||
} else if (strstr($view['wr_option'], 'html2')) {
|
||||
$html = 2;
|
||||
}
|
||||
|
||||
// 💡 [수정] HTML 태그가 포함되어 있으면 강제로 HTML 모드로 처리
|
||||
if ($html == 0 && preg_match('/<[a-z][\s\S]*>/i', $view['wr_content'])) {
|
||||
$html = 2; // HTML 태그가 발견되면 강제로 HTML2 모드 (모든 HTML 허용)
|
||||
}
|
||||
|
||||
if ($html > 0) {
|
||||
// 💡 [핵심] HTML 모드일 때는 원본 내용을 그대로 출력 (불필요한 br 태그 생성 방지)
|
||||
// g5_dynamic_img_url로 이미지 경로만 보정
|
||||
echo g5_dynamic_img_url($view['wr_content']);
|
||||
} else {
|
||||
// 일반 텍스트 모드일 때는 기존처럼 처리
|
||||
echo nl2br(get_text($view['wr_content']));
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($body_images)): ?>
|
||||
<div class="view-body-images">
|
||||
<?php foreach ($body_images as $image): ?>
|
||||
<figure class="body-image-item">
|
||||
<img src="<?php echo $image['path'].'/'.$image['file']; ?>" alt="<?php echo $image['source']; ?>">
|
||||
<figcaption><?php echo $image['content']; ?></figcaption>
|
||||
</figure>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="view-footer">
|
||||
<div class="btn-group-left">
|
||||
<?php if ($prev_href): ?><a href="<?php echo $prev_href ?>" class="btn btn-secondary">이전글</a><?php endif; ?>
|
||||
<?php if ($next_href): ?><a href="<?php echo $next_href ?>" class="btn btn-secondary">다음글</a><?php endif; ?>
|
||||
</div>
|
||||
<div class="btn-group-right">
|
||||
<a href="<?php echo $list_href ?>" class="btn btn-primary">목록</a>
|
||||
<?php if ($update_href): ?><a href="<?php echo $update_href ?>" class="btn btn-secondary">수정</a><?php endif; ?>
|
||||
<?php if ($delete_href): ?><a href="<?php echo $delete_href ?>" onclick="del(this.href); return false;" class="btn btn-secondary">삭제</a><?php endif; ?>
|
||||
<?php if ($write_href): ?><a href="<?php echo $write_href ?>" class="btn btn-primary">글쓰기</a><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* rb.board.core.coverage :: write.skin.php
|
||||
* 💡 [최종 수정] 그누보드 표준 방식을 준수하는 에디터 전환 기능
|
||||
*/
|
||||
|
||||
// 스킨 CSS 로드
|
||||
$_skin_url = G5_THEME_URL . '/skin/board/rb.board.core.coverage';
|
||||
add_stylesheet('<link rel="stylesheet" href="' . $_skin_url . '/style.css?ver=' . G5_SERVER_TIME . '">', 0);
|
||||
|
||||
// 💡 [추가] 메인 노출 관련 로직
|
||||
$main_view_max = null;
|
||||
|
||||
// 게시판 여분필드(bo_1 ~ bo_10) 중 제목이 'main_view_max'인 필드의 값을 가져옵니다.
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
if (isset($board['bo_'.$i.'_subj']) && $board['bo_'.$i.'_subj'] == 'main_view_max') {
|
||||
$main_view_max = $board['bo_'.$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$main_display_count = 0;
|
||||
$main_display_titles = '';
|
||||
|
||||
// main_view_max가 숫자이거나, 비어있거나, null일 때만 유효한 것으로 간주
|
||||
$is_main_view_max_valid = ($main_view_max === null || $main_view_max === '' || is_numeric($main_view_max));
|
||||
|
||||
if ($is_main_view_max_valid && is_numeric($main_view_max) && $main_view_max !== '') {
|
||||
$sql = "SELECT wr_subject FROM {$g5['write_prefix']}{$bo_table} WHERE wr_8 = 'Y'";
|
||||
if ($w == 'u') {
|
||||
// 수정 모드에서는 현재 글을 제외하고 카운트
|
||||
$sql .= " AND wr_id != '{$wr_id}'";
|
||||
}
|
||||
$result = sql_query($sql);
|
||||
$titles = array();
|
||||
while ($row = sql_fetch_array($result)) {
|
||||
$titles[] = $row['wr_subject'];
|
||||
}
|
||||
$main_display_count = count($titles);
|
||||
$main_display_titles = implode(', ', $titles);
|
||||
}
|
||||
|
||||
|
||||
$field_map = array(
|
||||
'summary' => 'wr_1',
|
||||
'featured' => 'wr_10',
|
||||
'main_display' => 'wr_8', // 💡 [추가] 메인 화면 노출 필드 매핑
|
||||
);
|
||||
$ebook_link_field = 'wr_link1';
|
||||
$cfg_write = isset($board_config['write']) ? $board_config['write'] : array();
|
||||
// $sql = "SELECT * FROM g5_board WHERE bo_table = 'newsfocus1'";
|
||||
// $result = sql_query($sql);
|
||||
|
||||
?>
|
||||
|
||||
<div id="coverage-board" class="board-write-container">
|
||||
<form name="fwrite" id="fwrite" action="<?php echo $action_url ?>" onsubmit="return fwrite_submit(this);" method="post" enctype="multipart/form-data" autocomplete="off" novalidate>
|
||||
<input type="hidden" name="uid" value="<?php echo get_uniqid(); ?>">
|
||||
<input type="hidden" name="w" value="<?php echo $w ?>">
|
||||
<input type="hidden" name="bo_table" value="<?php echo $bo_table ?>">
|
||||
<input type="hidden" name="wr_id" value="<?php echo $wr_id ?>">
|
||||
<input type="hidden" name="sca" value="<?php echo $sca ?>">
|
||||
<input type="hidden" name="sfl" value="<?php echo $sfl ?>">
|
||||
<input type="hidden" name="stx" value="<?php echo $stx ?>">
|
||||
<input type="hidden" name="spt" value="<?php echo $spt ?>">
|
||||
<input type="hidden" name="sst" value="<?php echo $sst ?>">
|
||||
<input type="hidden" name="sod" value="<?php echo $sod ?>">
|
||||
<input type="hidden" name="page" value="<?php echo $page ?>">
|
||||
|
||||
<div class="write-form-group">
|
||||
<label for="wr_subject" class="form-label">제목<span class="required">*</span></label>
|
||||
<input type="text" name="wr_subject" value="<?php echo $subject ?>" id="wr_subject" required class="form-control" placeholder="제목을 입력하세요">
|
||||
</div>
|
||||
|
||||
<?php if ($is_category): ?>
|
||||
<div class="write-form-group">
|
||||
<label for="ca_name" class="form-label">카테고리<span class="required">*</span></label>
|
||||
<select name="ca_name" id="ca_name" required class="form-control"><option value="">선택하세요</option><?php echo $category_option ?></select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($cfg_write['use_summary'])): ?>
|
||||
<div class="write-form-group">
|
||||
<label for="<?php echo $field_map['summary']; ?>" class="form-label"><?php echo $cfg_write['summary_label'] ?: '요약'; ?></label>
|
||||
<textarea name="<?php echo $field_map['summary']; ?>" id="<?php echo $field_map['summary']; ?>" class="form-control" rows="3" placeholder="<?php echo $cfg_write['summary_placeholder']; ?>"><?php echo $write[$field_map['summary']]; ?></textarea>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="write-form-group">
|
||||
<label for="wr_content" class="form-label">내용<span class="required">*</span></label>
|
||||
<div class="editor-toggle-buttons">
|
||||
<button type="button" class="btn btn-sm btn-editor-toggle <?php echo $is_dhtml_editor ? 'active' : ''; ?>" data-editor-type="dhtml">HTML 에디터</button>
|
||||
<button type="button" class="btn btn-sm btn-editor-toggle <?php echo $is_dhtml_editor ? '' : 'active'; ?>" data-editor-type="text">텍스트 에디터</button>
|
||||
</div>
|
||||
<div id="dhtml-editor-area" style="display: <?php echo $is_dhtml_editor ? 'block' : 'none'; ?>;">
|
||||
<?php if ($is_dhtml_editor) { echo $editor_html; } ?>
|
||||
</div>
|
||||
<div id="text-editor-area" style="display: <?php echo $is_dhtml_editor ? 'none' : 'block'; ?>;">
|
||||
<textarea id="wr_content_text" class="form-control" rows="10"><?php echo $content ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:none;">
|
||||
<?php if ($is_html) { ?>
|
||||
<input type="checkbox" id="html" name="html" value="html2" <?php echo ($html_value) ? "checked" : ""; ?>>
|
||||
<label for="html">html</label>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<hr class="form-divider">
|
||||
|
||||
<?php for ($i=1; $is_file && $i<=$board['bo_upload_count']; $i++):
|
||||
$file_label = isset($cfg_write['file_labels'][$i]) ? $cfg_write['file_labels'][$i] : '첨부파일 #'.$i;
|
||||
$file_text = isset($cfg_write['file_texts'][$i]) ? $cfg_write['file_texts'][$i] : '';
|
||||
?>
|
||||
<div class="write-form-group file-upload-group">
|
||||
<label for="bf_file_<?php echo $i ?>" class="form-label"><?php echo $file_label; ?><?php if($i==1) echo '<span class="required">*</span>'; ?></label>
|
||||
<div class="file-input-wrapper">
|
||||
<input type="file" name="bf_file[]" id="bf_file_<?php echo $i ?>" title="파일첨부 <?php echo $i ?> : 용량 <?php echo $upload_max_filesize ?> 이하만 업로드 가능" class="form-control" <?php if ($w=='' && $i==1) echo 'required'; ?>>
|
||||
<?php if ($w == 'u' && $file[$i-1]['file']): ?>
|
||||
<span class="file-delete-wrap"><input type="checkbox" id="bf_file_del_<?php echo $i-1 ?>" name="bf_file_del[<?php echo $i-1; ?>]" value="1"><label for="bf_file_del_<?php echo $i-1 ?>"><?php echo $file[$i-1]['source'].'('.$file[$i-1]['size'].')'; ?> 파일 삭제</label></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if($file_text): ?><p class="form-text"><?php echo $file_text; ?></p><?php endif; ?>
|
||||
</div>
|
||||
<?php endfor; ?>
|
||||
|
||||
<hr class="form-divider">
|
||||
|
||||
<?php if ($is_admin): ?>
|
||||
<div class="admin-options-group">
|
||||
<h3 class="form-section-title">관리자 전용 설정</h3>
|
||||
<div class="admin-option-item">
|
||||
<label class="form-check-label" for="is_main_display">
|
||||
<input type="checkbox" name="<?php echo $field_map['main_display']; ?>" value="Y" id="is_main_display" class="admin-option-checkbox" <?php echo ($write[$field_map['main_display']] == 'Y') ? 'checked' : ''; ?>>
|
||||
<span class="option-text">메인 화면 노출 (체크 시 메인 페이지 포트폴리오 영역에 노출됩니다)</span>
|
||||
</label>
|
||||
</div>
|
||||
<!-- <div class="admin-option-item">
|
||||
<label class="form-check-label" for="is_featured">
|
||||
<input type="checkbox" name="<?php /*echo $field_map['featured']; */?>" value="Y" id="is_featured" class="admin-option-checkbox" <?php /*echo ($write[$field_map['featured']] == 'Y') ? 'checked' : ''; */?>>
|
||||
<span class="option-text">이 글을 '지정 최신글'로 설정합니다. (최대 6개)</span>
|
||||
</label>
|
||||
<div id="ebook-link-group" style="display: <?php /*echo ($write[$field_map['featured']] == 'Y') ? 'block' : 'none'; */?>; margin-top: 15px;">
|
||||
<label for="<?php /*echo $ebook_link_field; */?>" class="form-label" style="margin-top:0;">E-book 링크</label>
|
||||
<input type="url" name="<?php /*echo $ebook_link_field; */?>" value="<?php /*echo $write[$ebook_link_field]; */?>" id="<?php /*echo $ebook_link_field; */?>" class="form-control" placeholder="https://example.com/ebook/123">
|
||||
<p class="form-text">'지정 최신글'로 설정했을 경우, 클릭 시 이동할 이북 주소를 입력하세요.</p>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="write-form-footer">
|
||||
<a href="<?php echo get_pretty_url($bo_table); ?>" class="btn btn-secondary">취소</a>
|
||||
<button type="submit" id="btn_submit" accesskey="s" class="btn btn-primary">작성완료</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<style>
|
||||
/* 에디터 토글 버튼 스타일 */
|
||||
.editor-toggle-buttons {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
.btn-editor-toggle {
|
||||
/* padding: 6px 12px; */
|
||||
font-size: 13px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #f8f9fa;
|
||||
color: #555;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.btn-editor-toggle:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
.btn-editor-toggle.active {
|
||||
background-color: #4a90e2;
|
||||
color: #fff;
|
||||
border-color: #4a90e2;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const isFeaturedCheckbox = document.getElementById('is_featured');
|
||||
const ebookLinkGroup = document.getElementById('ebook-link-group');
|
||||
if (isFeaturedCheckbox && ebookLinkGroup) {
|
||||
isFeaturedCheckbox.addEventListener('change', function() {
|
||||
ebookLinkGroup.style.display = this.checked ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
const dhtmlEditorArea = document.getElementById('dhtml-editor-area');
|
||||
const textEditorArea = document.getElementById('text-editor-area');
|
||||
const editorToggleButtons = document.querySelectorAll('.btn-editor-toggle');
|
||||
const wrContentTextarea = document.getElementById('wr_content_text');
|
||||
const htmlCheckbox = document.getElementById('html');
|
||||
|
||||
function setEditorMode(isDhtml) {
|
||||
if (isDhtml) {
|
||||
dhtmlEditorArea.style.display = 'block';
|
||||
textEditorArea.style.display = 'none';
|
||||
if (htmlCheckbox) htmlCheckbox.checked = true;
|
||||
if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances.wr_content) {
|
||||
CKEDITOR.instances.wr_content.setData(wrContentTextarea.value);
|
||||
}
|
||||
} else {
|
||||
dhtmlEditorArea.style.display = 'none';
|
||||
textEditorArea.style.display = 'block';
|
||||
if (htmlCheckbox) htmlCheckbox.checked = false;
|
||||
if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances.wr_content) {
|
||||
wrContentTextarea.value = CKEDITOR.instances.wr_content.getData();
|
||||
}
|
||||
}
|
||||
editorToggleButtons.forEach(btn => {
|
||||
if ((btn.dataset.editorType === 'dhtml' && isDhtml) || (btn.dataset.editorType === 'text' && !isDhtml)) {
|
||||
btn.classList.add('active');
|
||||
} else {
|
||||
btn.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setEditorMode(<?php echo $is_dhtml_editor ? 'true' : 'false'; ?>);
|
||||
|
||||
editorToggleButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const type = this.dataset.editorType;
|
||||
setEditorMode(type === 'dhtml');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function fwrite_submit(f) {
|
||||
const textEditorArea = document.getElementById('text-editor-area');
|
||||
if (textEditorArea.style.display === 'block') {
|
||||
f.wr_content.value = document.getElementById('wr_content_text').value;
|
||||
}
|
||||
|
||||
// 💡 [추가] 메인 노출 개수 제한 검사
|
||||
const mainDisplayCheckbox = document.getElementById('is_main_display');
|
||||
if (mainDisplayCheckbox && mainDisplayCheckbox.checked) {
|
||||
const mainViewMax = <?php echo json_encode($main_view_max); ?>;
|
||||
const isMainViewMaxValid = <?php echo json_encode($is_main_view_max_valid); ?>;
|
||||
|
||||
if (!isMainViewMaxValid) {
|
||||
alert('게시판의 "main_view_max" 여분 필드 설정값이 숫자가 아닙니다. 관리자에게 문의하여 설정을 수정해주세요.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mainViewMax !== null && mainViewMax !== '' && !isNaN(parseInt(mainViewMax))) {
|
||||
const mainViewMaxInt = parseInt(mainViewMax, 10);
|
||||
const mainDisplayCount = <?php echo (int)$main_display_count; ?>;
|
||||
|
||||
if (mainDisplayCount >= mainViewMaxInt) {
|
||||
const mainDisplayTitles = <?php echo json_encode($main_display_titles); ?>;
|
||||
alert('메인 노출 최대 개수(' + mainViewMaxInt + '개)를 초과하여 더 이상 설정할 수 없습니다.\n\n현재 설정된 글:\n' + mainDisplayTitles);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<?php echo $editor_js; ?>
|
||||
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user