first commit 2
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* ==========================================================================
|
||||
* 💡 베이스 모듈(Base Module) 전용 스타일시트
|
||||
* ==========================================================================
|
||||
*/
|
||||
|
||||
/* --- 1. 섹션 기본 스타일 --- */
|
||||
.item-section {
|
||||
width: 100%;
|
||||
padding: 80px 0;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
/* --- 2. 섹션 헤더 (제목, 부제) --- */
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.section-header .subtitle {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #0056b3;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 36px;
|
||||
font-weight: 900;
|
||||
color: #25282B;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.section-header p {
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* --- 3. 아이템 카드 그리드 --- */
|
||||
.item-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
/* --- 4. 개별 아이템 카드 --- */
|
||||
.item-card {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.item-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* --- 5. 카드 내부 요소 --- */
|
||||
.item-image {
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-image.is-patent {
|
||||
padding: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.item-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
.item-card:hover .item-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.item-info {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.item-info h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.item-info p {
|
||||
font-size: 0.95rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* --- 9. 스크롤 애니메이션 (공용) --- */
|
||||
.reveal-up, .reveal-fade {
|
||||
opacity: 0;
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
}
|
||||
.reveal-up { transform: translateY(40px); }
|
||||
.reveal-fade { transform: scale(0.95); }
|
||||
.reveal-up.is-revealed, .reveal-fade.is-revealed {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* --- 10. [모듈 전용] 이미지 팝업 모달 스타일 (개선) --- */
|
||||
.image-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1050;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px 20px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.image-modal.is-active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,.5);
|
||||
animation: modal-slide-down 0.4s ease-out;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@keyframes modal-slide-down {
|
||||
from {
|
||||
transform: translateY(-50px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content .modal-image {
|
||||
display: block;
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
object-fit: contain;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.modal-info {
|
||||
padding: 20px 25px;
|
||||
max-width: 800px; /* 텍스트 영역의 최대 너비는 제한 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-info .modal-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.modal-info .modal-desc {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
font-size: 35px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.5);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.close-btn:hover,
|
||||
.close-btn:focus {
|
||||
color: #ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
/* --- 11. [개선] 가독성 향상을 위한 줄바꿈 처리 --- */
|
||||
.section-header h2,
|
||||
.section-header p,
|
||||
.product-info-trend h3,
|
||||
.product-info-trend p,
|
||||
.item-info h3,
|
||||
.item-info p {
|
||||
word-break: keep-all;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
/* --- 12. [개선] 카드 설명 텍스트 잘림 방지 및 높이 고정 --- */
|
||||
.product-info-trend p,
|
||||
.item-info p {
|
||||
height: 3.04rem;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* --- 13. [최종 수정] 모듈 스크롤바 완전 숨김 처리 --- */
|
||||
/* 1. 기본 상태: 스크롤바를 완전히 투명하게 만듭니다. */
|
||||
.image-modal {
|
||||
/* Firefox: 스크롤바 색상을 양쪽 모두 투명하게 설정 */
|
||||
scrollbar-color: transparent transparent;
|
||||
scrollbar-width: thin;
|
||||
transition: scrollbar-color 0.3s ease;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar-thumb {
|
||||
/* Webkit: 스크롤바 막대를 투명하게 */
|
||||
background-color: transparent;
|
||||
border-radius: 10px;
|
||||
border: 3px solid transparent;
|
||||
background-clip: padding-box;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* 2. :hover 상태: 마우스를 올리면 스크롤바가 나타납니다. */
|
||||
.image-modal:hover {
|
||||
/* Firefox: 스크롤바 색상을 보이게 변경 */
|
||||
scrollbar-color: rgba(0, 0, 0, 0.4) transparent;
|
||||
}
|
||||
|
||||
.image-modal:hover::-webkit-scrollbar-thumb {
|
||||
/* Webkit: 스크롤바 막대 색상을 보이게 변경 */
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// TODO: 'initBaseModule'을 고유한 함수 이름으로 변경하세요. (예: initNewsModule)
|
||||
function initBaseModule(moduleId) {
|
||||
const moduleElement = document.getElementById(moduleId);
|
||||
if (!moduleElement || moduleElement.classList.contains('initialized')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const section = moduleElement.querySelector('.base-section');
|
||||
const itemGrid = moduleElement.querySelector('.item-grid');
|
||||
const modal = moduleElement.querySelector('.image-modal');
|
||||
|
||||
if (!section || !itemGrid || !modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
function renderGrid() {
|
||||
const itemsJson = section.dataset.items;
|
||||
let itemsData;
|
||||
|
||||
try {
|
||||
itemsData = JSON.parse(itemsJson);
|
||||
} catch (e) {
|
||||
itemGrid.innerHTML = '<p>데이터를 불러오는 데 실패했습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!itemsData || itemsData.length === 0) {
|
||||
itemGrid.innerHTML = '<p>표시할 항목이 없습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const itemCardsHTML = itemsData.map(item => `
|
||||
<div class="item-card js-modal-trigger" data-title="${item.title}" data-desc="${item.description}" data-img="${item.image}">
|
||||
<div class="item-image">
|
||||
<img src="${item.image}" alt="${item.title}">
|
||||
</div>
|
||||
<div class="item-info">
|
||||
<h3>${item.title}</h3>
|
||||
<p>${item.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
itemGrid.innerHTML = itemCardsHTML;
|
||||
}
|
||||
|
||||
function setupModalEvents() {
|
||||
const modalImage = modal.querySelector('.modal-image');
|
||||
const modalTitle = modal.querySelector('.modal-title');
|
||||
const modalDesc = modal.querySelector('.modal-desc');
|
||||
const closeBtn = modal.querySelector('.close-btn');
|
||||
|
||||
function closeModal() {
|
||||
modal.classList.remove('is-active');
|
||||
}
|
||||
|
||||
itemGrid.addEventListener('click', function(event) {
|
||||
const card = event.target.closest('.js-modal-trigger');
|
||||
if (card) {
|
||||
modalImage.src = card.dataset.img;
|
||||
modalTitle.textContent = card.dataset.title;
|
||||
modalDesc.textContent = card.dataset.desc;
|
||||
modal.classList.add('is-active');
|
||||
}
|
||||
});
|
||||
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
modal.addEventListener('click', (e) => (e.target === modal) && closeModal());
|
||||
document.addEventListener('keydown', (e) => (e.key === 'Escape' && modal.classList.contains('is-active')) && closeModal());
|
||||
}
|
||||
|
||||
renderGrid();
|
||||
setupModalEvents();
|
||||
moduleElement.classList.add('initialized');
|
||||
}
|
||||
|
||||
// TODO: 'initBaseModule'을 고유한 함수 이름으로 변경하세요.
|
||||
window.initBaseModule = initBaseModule;
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// =================================================================================
|
||||
// 💡 [사용법] 이 파일을 복사하여 새 모듈을 만들 때 아래 TODO 항목들을 수정하세요.
|
||||
// =================================================================================
|
||||
|
||||
// TODO: 'board_name'을 실제 게시판 테이블명으로 변경하세요. (예: 'gallery', 'news' 등)
|
||||
$bo_table_name = 'board_name';
|
||||
|
||||
// TODO: 가져올 게시물 수를 변경할 수 있습니다.
|
||||
$limit = 3;
|
||||
|
||||
// --- 데이터 처리 ---
|
||||
$module_data = array();
|
||||
$sql = " SELECT wr_id, wr_subject, wr_content FROM {$g5['write_prefix']}{$bo_table_name} WHERE wr_is_comment = 0 ORDER BY wr_num, wr_reply LIMIT {$limit} ";
|
||||
$result = sql_query($sql);
|
||||
|
||||
for ($i=0; $row=sql_fetch_array($result); $i++) {
|
||||
$files = get_file($bo_table_name, $row['wr_id']);
|
||||
$image_url = (isset($files[0]['path']) && isset($files[0]['file'])) ? $files[0]['path'].'/'.$files[0]['file'] : G5_THEME_URL.'/img/no_image.png';
|
||||
|
||||
$module_data[] = array(
|
||||
'id' => $row['wr_id'],
|
||||
'title' => get_text($row['wr_subject']),
|
||||
'description' => get_text(cut_str(strip_tags($row['wr_content']), 100)),
|
||||
'image' => $image_url
|
||||
);
|
||||
}
|
||||
$module_json = json_encode($module_data, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// CSS와 JS 파일의 버전을 파일 수정 시간으로 자동 갱신
|
||||
$module_css_path = G5_THEME_PATH.'/rb.custom/_base_module/module.css';
|
||||
$module_js_path = G5_THEME_PATH.'/rb.custom/_base_module/module.js';
|
||||
$module_css_ver = file_exists($module_css_path) ? filemtime($module_css_path) : G5_CSS_VER;
|
||||
$module_js_ver = file_exists($module_js_path) ? filemtime($module_js_path) : G5_JS_VER;
|
||||
|
||||
// 이 모듈만의 고유 ID를 생성합니다.
|
||||
$module_id = 'base_module_'.uniqid();
|
||||
?>
|
||||
|
||||
<!-- 모듈의 가장 바깥 요소에 고유 ID를 부여합니다. -->
|
||||
<div id="<?php echo $module_id; ?>" class="base-module">
|
||||
<section class="item-section" data-items='<?php echo htmlspecialchars($module_json, ENT_QUOTES, 'UTF-8'); ?>'>
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<!-- TODO: 모듈의 제목과 설명을 수정하세요. -->
|
||||
<span class="subtitle">Module Subtitle</span>
|
||||
<h2>모듈 제목</h2>
|
||||
<p>이곳에 모듈에 대한 간단한 설명을 입력하세요.</p>
|
||||
</div>
|
||||
<div class="item-grid">
|
||||
<!-- JS로 아이템 카드가 생성될 영역 -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 모듈 내부에 모달 HTML을 포함시킵니다. -->
|
||||
<div class="image-modal">
|
||||
<div class="modal-content">
|
||||
<span class="close-btn">×</span>
|
||||
<img class="modal-image" src="" alt="이미지">
|
||||
<div class="modal-info">
|
||||
<h3 class="modal-title"></h3>
|
||||
<p class="modal-desc"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 모듈에 필요한 CSS 파일을 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/_item_module/module.css?ver=<?php echo $module_css_ver; ?>">
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const currentModuleId = '<?php echo $module_id; ?>';
|
||||
// TODO: 'inititemModule'을 고유한 함수 이름으로 변경하세요. (예: initNewsModule)
|
||||
const initFunctionName = 'inititemModule';
|
||||
// TODO: 'item-module-script'를 고유한 스크립트 ID로 변경하세요. (예: news-module-script)
|
||||
const scriptId = 'item-module-script';
|
||||
|
||||
if (document.getElementById(scriptId)) {
|
||||
if (typeof window[initFunctionName] === 'function') {
|
||||
window[initFunctionName](currentModuleId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
// TODO: JS 파일 경로를 실제 모듈 경로로 수정하세요.
|
||||
script.src = '<?php echo G5_THEME_URL; ?>/rb.custom/_base_module/module.js?ver=<?php echo $module_js_ver; ?>';
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
if (typeof window[initFunctionName] === 'function') {
|
||||
window[initFunctionName](currentModuleId);
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
?>
|
||||
<!-- 💡 [핵심] 사이트 전체에서 사용할 공용 문의하기 모달입니다. 기본적으로 숨겨져 있습니다. -->
|
||||
<div id="global-contact-modal" class="global-contact-modal-container" style="display: none;">
|
||||
<div class="modal-overlay-bg"></div>
|
||||
<div class="modal-content-wrapper">
|
||||
<button type="button" class="modal-close">×</button>
|
||||
<div class="section-header">
|
||||
<span class="subtitle">Contact Us</span>
|
||||
<h2>공간의 가능성을 열어보세요.</h2>
|
||||
<p>성진미도어의 전문가와 상담하고, 당신의 공간에 꼭 맞는 솔루션을 찾아보세요.</p>
|
||||
</div>
|
||||
<div class="contact-wrapper">
|
||||
<div class="contact-info">
|
||||
<h3>Information</h3>
|
||||
<div class="info-item"><strong>본사 및 전시장</strong><p>충청남도 아산시 음봉면 월산로 128-130</p></div>
|
||||
<div class="info-item"><strong>대표 연락처</strong><p>T. 041-532-0555 / H. 010-5434-4126</p></div>
|
||||
<div class="info-item"><strong>청주 전시장</strong><p>T. 043-235-2352 / H. 010-2066-4126</p></div>
|
||||
<div class="info-item"><strong>운영시간</strong><p>평일 09:00 - 18:00 (주말 및 공휴일 휴무)</p></div>
|
||||
</div>
|
||||
<form name="contactForm" id="contactForm" class="contact-form" method="post">
|
||||
<h3>상담 신청</h3>
|
||||
<div id="form-messages" class="form-message-area"></div>
|
||||
<input type="text" name="contact_name" placeholder="이름" required>
|
||||
<input type="tel" name="contact_hp" placeholder="연락처" required>
|
||||
<input type="email" name="contact_email" placeholder="이메일" required>
|
||||
<textarea name="contact_message" placeholder="문의 내용을 입력해주세요." rows="5" required></textarea>
|
||||
<button type="submit" id="contact-submit-btn" class="cta-button">상담 신청하기</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
/* 독립 문의하기 모듈 스타일 */
|
||||
.contact-section-trigger { padding: 80px 0; text-align: center; background-color: #f8f9fa; }
|
||||
.contact-section-trigger .cta-button { padding: 15px 30px; border-radius: 50px; font-weight: 700; }
|
||||
|
||||
.contact-modal-local { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1010; }
|
||||
.contact-modal-local.is-active { display: block; }
|
||||
.contact-modal-local .modal-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); animation: fadeIn 0.3s ease; }
|
||||
.contact-modal-local .modal-content-local { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 900px; background: #fff; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); animation: slideDown 0.4s ease-out; padding: 40px; }
|
||||
.contact-modal-local .modal-close { position: absolute; top: 15px; right: 20px; font-size: 2rem; color: #aaa; background: none; border: none; cursor: pointer; line-height: 1; }
|
||||
|
||||
.contact-modal-local .section-header { text-align: center; margin-bottom: 40px; }
|
||||
.contact-modal-local .section-header .subtitle { color: #0056b3; }
|
||||
.contact-modal-local .section-header h2 { font-size: 2rem; }
|
||||
.contact-modal-local .section-header p { max-width: 100%; }
|
||||
|
||||
.contact-wrapper { display: flex; gap: 40px; }
|
||||
.contact-info, .contact-form { flex: 1; }
|
||||
.contact-info h3, .contact-form h3 { font-size: 1.3rem; margin-bottom: 20px; border-bottom: 2px solid #eee; padding-bottom: 15px; }
|
||||
.info-item { margin-bottom: 15px; }
|
||||
.info-item strong { display: block; font-weight: 700; margin-bottom: 5px; }
|
||||
.info-item p { margin: 0; color: #666; }
|
||||
|
||||
.contact-form input, .contact-form textarea { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 5px; margin-bottom: 15px; }
|
||||
.contact-form .cta-button { width: 100%; padding: 15px; }
|
||||
.contact-form .cta-button:disabled { background-color: #ccc; cursor: not-allowed; }
|
||||
|
||||
.form-message-area .message { padding: 10px; margin-bottom: 15px; border-radius: 5px; text-align: center; }
|
||||
.form-message-area .success { background-color: #d4edda; color: #155724; }
|
||||
.form-message-area .error { background-color: #f8d7da; color: #721c24; }
|
||||
|
||||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||
@keyframes slideDown { from { opacity: 0; transform: translate(-50%, -60%); } to { opacity: 1; transform: translate(-50%, -50%); } }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contact-wrapper { flex-direction: column; }
|
||||
.contact-modal-local .modal-content-local { padding: 25px; max-height: 85vh; overflow-y: auto; }
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
function initContactModule(moduleId) {
|
||||
const moduleElement = document.getElementById(moduleId);
|
||||
if (!moduleElement || moduleElement.classList.contains('initialized')) return;
|
||||
|
||||
const openBtn = moduleElement.querySelector('.btn-open-contact-modal');
|
||||
const modal = moduleElement.querySelector('.contact-modal-local');
|
||||
const closeBtn = modal.querySelector('.modal-close');
|
||||
const overlay = modal.querySelector('.modal-overlay');
|
||||
const form = modal.querySelector('form');
|
||||
const formMessages = modal.querySelector('.form-message-area');
|
||||
|
||||
const openModal = () => {
|
||||
modal.classList.add('is-active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
modal.classList.remove('is-active');
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
|
||||
openBtn.addEventListener('click', openModal);
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
overlay.addEventListener('click', closeModal);
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && modal.classList.contains('is-active')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// 💡 [핵심 수정] universalMailer를 사용한 폼 제출 로직
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const submitBtn = this.querySelector('button[type="submit"]');
|
||||
const originalBtnText = submitBtn.textContent;
|
||||
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = '전송 중...';
|
||||
formMessages.innerHTML = ''; // 이전 메시지 초기화
|
||||
|
||||
const formData = new FormData(form);
|
||||
const variables = {
|
||||
contact_name: formData.get('contact_name'),
|
||||
contact_hp: formData.get('contact_hp'),
|
||||
contact_email: formData.get('contact_email'),
|
||||
contact_message: formData.get('contact_message').replace(/\n/g, '<br>')
|
||||
};
|
||||
|
||||
// universalMailer 객체가 있는지 확인
|
||||
if (window.universalMailer && typeof window.universalMailer.send === 'function') {
|
||||
window.universalMailer.send({
|
||||
template_code: 'contact_inquiry', // 관리자에서 생성한 템플릿 코드
|
||||
// to_email: variables.contact_email, //수신자임 문의 하기 같은경우 관리자가 받아야 해서 비워둔다
|
||||
variables: variables,
|
||||
onSuccess: function(response) {
|
||||
alert(response.message || '상담 신청이 성공적으로 접수되었습니다.');
|
||||
form.reset();
|
||||
closeModal();
|
||||
},
|
||||
onError: function(errorMessage) {
|
||||
formMessages.innerHTML = `<div class="message error">${errorMessage || '오류가 발생했습니다.'}</div>`;
|
||||
},
|
||||
onComplete: function() {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = originalBtnText;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
alert('메일 발송 기능에 오류가 발생했습니다. 관리자에게 문의해주세요.');
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = originalBtnText;
|
||||
}
|
||||
});
|
||||
|
||||
moduleElement.classList.add('initialized');
|
||||
}
|
||||
|
||||
window.initContactModule = initContactModule;
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
|
||||
// CSS와 JS 파일의 버전을 파일 수정 시간으로 자동 갱신
|
||||
$module_css_path = G5_THEME_PATH.'/rb.custom/contact/module.css';
|
||||
$module_js_path = G5_THEME_PATH.'/rb.custom/contact/module.js';
|
||||
$module_css_ver = file_exists($module_css_path) ? filemtime($module_css_path) : G5_CSS_VER;
|
||||
$module_js_ver = file_exists($module_js_path) ? filemtime($module_js_path) : G5_JS_VER;
|
||||
|
||||
// 이 모듈만의 고유 ID를 생성합니다.
|
||||
$module_id = 'contact_module_'.uniqid();
|
||||
?>
|
||||
|
||||
<!-- 모듈의 가장 바깥 요소에 고유 ID를 부여합니다. -->
|
||||
<div id="<?php echo $module_id; ?>" class="contact-module">
|
||||
|
||||
<!-- 💡 [핵심] 이 모듈에 종속된 모달 HTML (사용자가 제공한 디자인 적용) -->
|
||||
<div class="contact-modal-local">
|
||||
<div class="modal-overlay"></div>
|
||||
<div class="modal-content-local">
|
||||
<button type="button" class="modal-close">×</button>
|
||||
<div class="section-header">
|
||||
<span class="subtitle">Contact Us</span>
|
||||
<h2>공간의 가능성을 열어보세요.</h2>
|
||||
<p>성진미도어의 전문가와 상담하고, 당신의 공간에 꼭 맞는 솔루션을 찾아보세요.</p>
|
||||
</div>
|
||||
<div class="contact-wrapper">
|
||||
<div class="contact-info">
|
||||
<h3>Information</h3>
|
||||
<div class="info-item"><strong>본사 및 전시장</strong><p>충청남도 아산시 음봉면 월산로 128-130</p></div>
|
||||
<div class="info-item"><strong>대표 연락처</strong><p>T. 041-532-0555 / H. 010-5434-4126</p></div>
|
||||
<div class="info-item"><strong>청주 전시장</strong><p>T. 043-235-2352 / H. 010-2066-4126</p></div>
|
||||
<div class="info-item"><strong>운영시간</strong><p>평일 09:00 - 18:00 (주말 및 공휴일 휴무)</p></div>
|
||||
</div>
|
||||
<form name="fcontactform_<?php echo $module_id; ?>" id="fcontactform_<?php echo $module_id; ?>" class="contact-form" method="post">
|
||||
<h3>상담 신청</h3>
|
||||
<div class="form-message-area"></div>
|
||||
<input type="text" name="contact_name" placeholder="이름" required>
|
||||
<input type="tel" name="contact_hp" placeholder="연락처" required>
|
||||
<input type="email" name="contact_email" placeholder="이메일" required>
|
||||
<textarea name="contact_message" placeholder="문의 내용을 입력해주세요." rows="5" required></textarea>
|
||||
<button type="submit" class="cta-button">상담 신청하기</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 💡 [핵심] 모듈의 실제 내용 (페이지에 표시될 부분) -->
|
||||
<div class="contact-section-trigger">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<span class="subtitle">Get a Quote</span>
|
||||
<h2>궁금한 점이 있으신가요?</h2>
|
||||
<p>전문가의 상담을 통해 당신의 공간에 가장 적합한 솔루션을 찾아보세요.</p>
|
||||
</div>
|
||||
<button type="button" class="btn-open-contact-modal cta-button">무료 상담 신청하기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 모듈에 필요한 CSS와 JS를 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/contact/module.css?ver=<?php echo $module_css_ver; ?>">
|
||||
<script>
|
||||
(function() {
|
||||
const currentModuleId = '<?php echo $module_id; ?>';
|
||||
const scriptId = 'contact-module-script';
|
||||
|
||||
if (document.getElementById(scriptId)) {
|
||||
if (typeof window.initContactModule === 'function') {
|
||||
window.initContactModule(currentModuleId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.src = '<?php echo G5_THEME_URL; ?>/rb.custom/contact/module.js?ver=<?php echo $module_js_ver; ?>';
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
if (typeof window.initContactModule === 'function') {
|
||||
window.initContactModule(currentModuleId);
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
|
||||
// 1. 탭 모듈 함수가 정의된 파일을 포함합니다.
|
||||
include_once(G5_THEME_PATH.'/rb.custom/tabs/tab_module.php');
|
||||
|
||||
// 2. 탭으로 표시할 내용을 배열로 정의합니다.
|
||||
$main_tabs_config = [
|
||||
[
|
||||
'title' => '공지사항', // 탭에 표시될 이름
|
||||
'type' => 'board', // 타입: 'board' (게시판)
|
||||
'id' => 'notice', // 게시판 ID (bo_table)
|
||||
'options' => ['rows' => 5, 'subject_len' => 40] // 옵션
|
||||
],
|
||||
[
|
||||
'title' => '회사소개', // 탭에 표시될 이름
|
||||
'type' => 'content', // 타입: 'content' (콘텐츠 페이지)
|
||||
'id' => 'company', // 콘텐츠 ID (co_id)
|
||||
],
|
||||
[
|
||||
'title' => '갤러리',
|
||||
'type' => 'board',
|
||||
'id' => 'gallery',
|
||||
'options' => ['rows' => 5, 'subject_len' => 35]
|
||||
],
|
||||
];
|
||||
|
||||
// 3. 설정 배열을 인자로 하여 탭 모듈 함수를 호출하고 출력합니다.
|
||||
echo rb_tabs($main_tabs_config);
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
/* --- STORY 섹션 레이아웃 --- */
|
||||
.story-section {
|
||||
width: 100%;
|
||||
padding: 80px 0;
|
||||
background-color: #f8f9fa;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 📌 [분할] 내용과 미디어가 함께 있는 경우 (좌우 2단) */
|
||||
.story-layout-split {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
}
|
||||
.story-layout-split .story-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: left; /* 기본 좌측 정렬 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
/* 💡 [수정] 분할 레이아웃일 때 제목(h2)만 가운데 정렬 */
|
||||
.story-layout-split .story-text h2 {
|
||||
text-align: center;
|
||||
}
|
||||
.story-layout-split .story-image {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: block; /* 이미지 영역 보이기 */
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
/*aspect-ratio: 4 / 3;*/
|
||||
}
|
||||
|
||||
/* 📌 [전체] 내용만 있는 경우 (텍스트가 중앙에 넓게 배치) */
|
||||
.story-layout-full {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.story-layout-full .story-text {
|
||||
flex: none;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
text-align: center; /* 모든 텍스트 가운데 정렬 */
|
||||
}
|
||||
.story-layout-full .story-image {
|
||||
display: none; /* 이미지/슬라이더 영역 숨김 */
|
||||
}
|
||||
|
||||
/* 공통 텍스트 스타일 */
|
||||
.story-text .subtitle {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--accent-color);
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
text-align: center; /* 💡 추가: 텍스트 가운데 정렬 */
|
||||
}
|
||||
/* h2는 각 레이아웃 클래스에서 정렬을 제어하므로 여기서는 공통 스타일만 정의 */
|
||||
.story-text h2 {
|
||||
font-size: 36px;
|
||||
font-weight: 900;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.story-text p {
|
||||
font-size: 16px;
|
||||
line-height: 1.8;
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
.story-text img,
|
||||
.story-text video {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* --- 슬라이더(Swiper) 스타일 --- */
|
||||
.story-slider {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.story-slider .swiper-slide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.story-slider img,
|
||||
.story-slider video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.story-slider .swiper-pagination-bullet {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
.story-slider .swiper-pagination-bullet-active {
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
/* 📌 [추가] DB에 게시물이 없을 때의 기본 레이아웃 (위아래 배치) */
|
||||
.story-layout-static {
|
||||
display: flex;
|
||||
flex-direction: column; /* 💡 핵심: 아이템을 세로로 쌓습니다. */
|
||||
align-items: center; /* 가운데 정렬 */
|
||||
gap: 40px; /* 텍스트와 이미지 사이의 간격 */
|
||||
text-align: center; /* 모든 텍스트 가운데 정렬 */
|
||||
}
|
||||
|
||||
.story-layout-static .story-text {
|
||||
max-width: 800px; /* 텍스트 최대 너비 제한 */
|
||||
}
|
||||
|
||||
.story-layout-static .story-image {
|
||||
width: 100%;
|
||||
max-width: 800px; /* 이미지 최대 너비 제한 */
|
||||
}
|
||||
|
||||
.story-layout-static .story-image img {
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
}
|
||||
/* 반응형 스타일 */
|
||||
@media (max-width: 768px) {
|
||||
.story-layout-split {
|
||||
flex-direction: column;
|
||||
}
|
||||
.story-text h2 {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 10. [모듈 전용] 이미지 팝업 모달 스타일 (개선) --- */
|
||||
.image-modal {
|
||||
display: none; /* 기본적으로 숨김 */
|
||||
position: fixed;
|
||||
z-index: 1050;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto; /* 내용이 클 경우 스크롤 */
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px 20px; /* 화면 가장자리와 여백 */
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.image-modal.is-active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
/* 💡 [수정] 고정된 max-width를 제거하여 이미지 크기에 맞춰 유연하게 변하도록 합니다. */
|
||||
width: auto; /* 너비를 자동으로 설정 */
|
||||
max-width: 100%; /* 화면 너비를 넘지 않도록 설정 */
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,.5);
|
||||
animation: modal-slide-down 0.4s ease-out;
|
||||
/*overflow: hidden;*/
|
||||
display: flex; /* 내부 요소 정렬을 위해 flex 사용 */
|
||||
flex-direction: column; /* 이미지와 텍스트를 세로로 쌓음 */
|
||||
}
|
||||
|
||||
@keyframes modal-slide-down {
|
||||
from {
|
||||
transform: translateY(-50px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 💡 [핵심 수정] 이미지 자체에 최대 크기를 지정합니다. */
|
||||
.modal-content .modal-image {
|
||||
display: block;
|
||||
/* 화면 너비의 90%를 넘지 않도록 설정 */
|
||||
max-width: 90vw;
|
||||
/* 화면 높이의 80%를 넘지 않도록 설정 (텍스트 공간 확보) */
|
||||
max-height: 80vh;
|
||||
/* 💡 [핵심] 이미지가 잘리지 않고, 비율을 유지하며 주어진 공간 안에 꽉 차게 표시됩니다. */
|
||||
object-fit: contain;
|
||||
/* 💡 [수정] width와 height를 auto로 설정하여 원본 비율을 따르도록 합니다. */
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.modal-info {
|
||||
padding: 20px 25px;
|
||||
/* 💡 [추가] 텍스트가 많아질 경우를 대비 */
|
||||
max-width: 800px; /* 텍스트 영역의 최대 너비는 제한 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-info .modal-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.modal-info .modal-desc {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
font-size: 35px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.5);
|
||||
z-index: 10; /* 이미지 위에 표시되도록 z-index 추가 */
|
||||
}
|
||||
|
||||
.close-btn:hover,
|
||||
.close-btn:focus {
|
||||
color: #ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
/* --- 11. [개선] 가독성 향상을 위한 줄바꿈 처리 --- */
|
||||
.section-header h2,
|
||||
.section-header p,
|
||||
.product-info-trend h3,
|
||||
.product-info-trend p,
|
||||
.item-info h3,
|
||||
.item-info p {
|
||||
/* 💡 [핵심] 한글 단어가 중간에 잘리는 현상을 방지합니다. */
|
||||
word-break: keep-all;
|
||||
|
||||
/* 💡 [보완] keep-all을 보완: 매우 긴 영단어나 URL이 있을 경우
|
||||
강제로 줄바꿈하여 레이아웃이 깨지는 것을 방지합니다. */
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
/* --- 12. [개선] 카드 설명 텍스트 잘림 방지 및 높이 고정 --- */
|
||||
.product-info-trend p,
|
||||
.item-info p {
|
||||
/* 1. 텍스트가 여러 줄로 표시될 수 있도록 최소/최대 높이를 확보합니다. */
|
||||
/* (폰트 크기 0.95rem * 줄간격 1.6 * 2줄) */
|
||||
height: 3.04rem;
|
||||
|
||||
/* 2. 웹킷 브라우저(크롬, 사파리 등)를 위한 멀티라인 생략(...) 처리 */
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2; /* 💡 최대 2줄까지만 표시합니다. */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
/* 3. 줄간격을 다시 한번 명확하게 지정합니다. */
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
|
||||
/* --- 13. [개선] 모달 스크롤바 스타일링 (보였다 사라지는 효과) --- */
|
||||
/* Firefox 스크롤바 스타일 */
|
||||
.image-modal {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 0, 0, 0.4) transparent;
|
||||
}
|
||||
|
||||
/* Webkit 브라우저 (크롬, 사파리 등) 스크롤바 스타일 */
|
||||
.image-modal::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar-track {
|
||||
background: transparent; /* 트랙은 항상 투명 */
|
||||
}
|
||||
|
||||
/* 기본 상태에서는 스크롤바 막대를 투명하게 만듭니다. */
|
||||
.image-modal::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
border-radius: 10px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* 모달 위에 마우스를 올렸을 때만 스크롤바 막대가 보이도록 합니다. */
|
||||
.image-modal:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// 이 스크립트는 main_visual 모듈이 로드될 때 즉시 실행됩니다.
|
||||
(function() {
|
||||
const storySliderEl = document.querySelector('.story-slider');
|
||||
|
||||
// 슬라이더 요소가 없거나, 이미 초기화되었다면 중복 실행을 방지합니다.
|
||||
if (!storySliderEl || storySliderEl.classList.contains('swiper-initialized')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬라이더 내의 모든 비디오를 찾아 리셋하는 함수
|
||||
* @param {HTMLElement} sliderElement - 슬라이더 컨테이너 요소
|
||||
*/
|
||||
const resetAllVideos = (sliderElement) => {
|
||||
sliderElement.querySelectorAll('video').forEach(video => {
|
||||
if (!video.paused) {
|
||||
video.pause();
|
||||
}
|
||||
video.currentTime = 0;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 현재 활성화된 슬라이드를 처리하는 함수
|
||||
* @param {object} swiper - Swiper 인스턴스
|
||||
*/
|
||||
const handleActiveSlide = (swiper) => {
|
||||
// 💡 [안정성 강화] swiper 객체가 유효한지 확인 후 진행합니다.
|
||||
if (!swiper || !swiper.el) {
|
||||
console.error("handleActiveSlide: 유효하지 않은 Swiper 인스턴스입니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 다른 모든 비디오를 먼저 리셋합니다.
|
||||
resetAllVideos(swiper.el);
|
||||
|
||||
const activeSlide = swiper.slides[swiper.activeIndex];
|
||||
const activeVideo = activeSlide?.querySelector('video');
|
||||
|
||||
if (activeSlide?.dataset?.type === 'video' && activeVideo) {
|
||||
// 활성 슬라이드가 비디오일 경우, 자동재생을 멈춥니다.
|
||||
swiper.autoplay.stop();
|
||||
|
||||
// 비디오를 재생합니다. (브라우저 정책에 의한 실패 대비)
|
||||
activeVideo.play().catch(error => {
|
||||
console.error("비디오 자동재생이 차단되었습니다:", error);
|
||||
// 재생에 실패하면 다음 슬라이드로 즉시 이동합니다.
|
||||
swiper.slideNext();
|
||||
});
|
||||
|
||||
// 비디오가 끝나면 다음 슬라이드로 이동하도록 이벤트를 설정합니다.
|
||||
activeVideo.onended = () => {
|
||||
swiper.slideNext();
|
||||
};
|
||||
} else {
|
||||
// 활성 슬라이드가 이미지일 경우, 자동재생을 다시 시작합니다.
|
||||
swiper.autoplay.start();
|
||||
}
|
||||
};
|
||||
|
||||
// Swiper 라이브러리가 로드되었는지 확인 후 슬라이더를 초기화합니다.
|
||||
if (typeof Swiper !== 'undefined') {
|
||||
const swiper = new Swiper(storySliderEl, {
|
||||
loop: true,
|
||||
effect: 'fade',
|
||||
fadeEffect: {
|
||||
crossFade: true
|
||||
},
|
||||
pagination: {
|
||||
el: '.swiper-pagination',
|
||||
clickable: true,
|
||||
},
|
||||
autoplay: {
|
||||
delay: 5000, // 💡 [개선] 비디오 재생을 고려하여 딜레이를 5초로 늘립니다.
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
on: {
|
||||
// 💡 [수정] 'this'를 사용하여 Swiper 인스턴스를 안정적으로 전달합니다.
|
||||
slideChange: function () {
|
||||
handleActiveSlide(this);
|
||||
},
|
||||
init: function () {
|
||||
handleActiveSlide(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 초기화되었음을 표시하여 중복 실행을 막습니다.
|
||||
storySliderEl.classList.add('swiper-initialized');
|
||||
} else {
|
||||
console.error('Swiper 라이브러리가 로드되지 않았습니다.');
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
|
||||
// --- (기존 PHP 데이터 처리 코드는 그대로 둡니다) ---
|
||||
$main_visual_post = null;
|
||||
$main_visual_files = [];
|
||||
$layout_class = '';
|
||||
$today = G5_TIME_YMD;
|
||||
|
||||
$sql = " SELECT * FROM {$g5['write_prefix']}main_visual
|
||||
WHERE wr_is_comment = 0 AND wr_10 = '0' AND (wr_1 = 'IMMEDIATE' OR (wr_1 = 'RESERVED' AND '{$today}' BETWEEN wr_2 AND wr_3))
|
||||
ORDER BY CASE wr_1 WHEN 'IMMEDIATE' THEN 1 ELSE 2 END, wr_num, wr_reply LIMIT 1 ";
|
||||
$main_visual_post = sql_fetch($sql);
|
||||
|
||||
if ($main_visual_post) {
|
||||
$layout_class = 'story-layout-full';
|
||||
$temp_files = get_file('main_visual', $main_visual_post['wr_id']);
|
||||
if (isset($temp_files) && $temp_files['count'] > 0) {
|
||||
for ($i = 0; $i < $temp_files['count']; $i++) {
|
||||
if (!isset($temp_files[$i]['file']) || !$temp_files[$i]['file']) continue;
|
||||
$file_ext = strtolower(pathinfo($temp_files[$i]['file'], PATHINFO_EXTENSION));
|
||||
$is_video = in_array($file_ext, ['mp4', 'mov', 'webm']);
|
||||
$main_visual_files[] = ['url' => $temp_files[$i]['path'].'/'.$temp_files[$i]['file'], 'type' => $is_video ? 'video' : 'image'];
|
||||
}
|
||||
}
|
||||
$has_media_in_content = preg_match('/<img|<video/i', $main_visual_post['wr_content']);
|
||||
if ($has_media_in_content) {
|
||||
$layout_class = (count($main_visual_files) > 0) ? 'story-layout-split' : 'story-layout-full';
|
||||
} else {
|
||||
$layout_class = (count($main_visual_files) > 0) ? 'story-layout-static' : 'story-layout-full';
|
||||
}
|
||||
} else {
|
||||
$layout_class = 'story-layout-static';
|
||||
}
|
||||
// --- (PHP 코드 끝) ---
|
||||
?>
|
||||
|
||||
<!-- 💡 [최종 수정] section에 'rb-autounwrap' 클래스를 추가하여 스마트 모듈임을 선언합니다. -->
|
||||
<section id="story" class="story-section">
|
||||
<div class="container <?php echo $layout_class; ?>">
|
||||
<?php if ($main_visual_post) { // 표시할 게시물이 있을 경우 ?>
|
||||
<div class="story-text">
|
||||
<span class="subtitle">Our Vision</span>
|
||||
<h2><?php echo get_text($main_visual_post['wr_subject']); ?></h2>
|
||||
<?php echo conv_content($main_visual_post['wr_content'], 1); ?>
|
||||
</div>
|
||||
<div class="story-image">
|
||||
<?php if (count($main_visual_files) > 0) { // 첨부파일이 있을 경우 슬라이더 표시 ?>
|
||||
<div class="swiper-container story-slider">
|
||||
<div class="swiper-wrapper">
|
||||
<?php foreach ($main_visual_files as $file) { ?>
|
||||
<div class="swiper-slide" data-type="<?php echo $file['type']; ?>">
|
||||
<?php if ($file['type'] === 'video') { ?>
|
||||
<video src="<?php echo $file['url']; ?>" muted playsinline loop autoplay></video>
|
||||
<?php } else { ?>
|
||||
<img src="<?php echo $file['url']; ?>" alt="메인 비주얼 이미지">
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="swiper-pagination"></div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } else { // 표시할 게시물이 없을 경우 (기존 정적 내용) ?>
|
||||
<div class="story-text">
|
||||
<span class="subtitle">Our Vision</span>
|
||||
<h2>문을 열면, 삶이 달라져야 한다고 믿습니다.</h2>
|
||||
<p>성진미도어는 국내 중문 시장 최초로 여닫이와 미닫이 기능을 복합한 ‘프리도어’를 개발했습니다. 시판과 특판 모두를 아우를 수 있는 기술력으로, 일상의 흐름을 바꾸는 문을 만듭니다. 중문 시장의 한줄기 빛이 되도록, 오늘도 한 걸음 더 나아갑니다.</p>
|
||||
</div>
|
||||
<div class="story-image">
|
||||
<img src="<?php echo G5_THEME_URL ?>/img/mainimage/main1.png" alt="미래 지향적인 디자인의 문">
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 💡 [핵심] 이 모듈에 필요한 CSS와 JS 파일을 모두 이곳에서 직접 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/main_visual/module.css?ver=<?php echo G5_CSS_VER; ?>">
|
||||
<script src="<?php echo G5_THEME_URL; ?>/rb.custom/main_visual/module.js?ver=<?php echo G5_JS_VER; ?>"></script>
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* ==========================================================================
|
||||
* 💡 products_section 모듈 전용 스타일시트
|
||||
* ==========================================================================
|
||||
*/
|
||||
|
||||
/* --- 1. 섹션 기본 스타일 --- */
|
||||
.products-trend-section {
|
||||
width: 100%;
|
||||
padding: 80px 0;
|
||||
background-color: #ffffff; /* 또는 원하는 배경색 */
|
||||
}
|
||||
|
||||
/* --- 2. 섹션 헤더 (제목, 부제) --- */
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.section-header .subtitle {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #0056b3; /* 포인트 색상 */
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 36px;
|
||||
font-weight: 900;
|
||||
color: #25282B; /* 기본 텍스트 색상 */
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.section-header p {
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* --- 3. 제품 카드 그리드 --- */
|
||||
.product-grid {
|
||||
display: grid;
|
||||
/* 💡 화면 크기에 따라 1~3개의 컬럼으로 자동 조정됩니다. */
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
/* --- 4. 개별 제품 카드 --- */
|
||||
.product-card-trend {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.product-card-trend:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* --- 5. 카드 내부 요소 --- */
|
||||
.product-image-trend {
|
||||
width: 100%;
|
||||
/* 💡 이미지 비율을 4:3으로 유지합니다. */
|
||||
aspect-ratio: 4 / 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-image-trend.is-patent {
|
||||
padding: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.product-image-trend img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; /* 이미지가 잘리지 않고 꽉 차도록 설정 */
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
.product-card-trend:hover .product-image-trend img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.product-info-trend {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.product-info-trend h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.product-info-trend p {
|
||||
font-size: 0.95rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* --- 9. 스크롤 애니메이션 (style_prestige_1.css에서 가져옴) --- */
|
||||
.reveal-up, .reveal-fade {
|
||||
opacity: 0;
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
}
|
||||
.reveal-up { transform: translateY(40px); }
|
||||
.reveal-fade { transform: scale(0.95); }
|
||||
.reveal-up.is-revealed, .reveal-fade.is-revealed {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* --- 10. [모듈 전용] 이미지 팝업 모달 스타일 (개선) --- */
|
||||
.image-modal {
|
||||
display: none; /* 기본적으로 숨김 */
|
||||
position: fixed;
|
||||
z-index: 1050;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto; /* 내용이 클 경우 스크롤 */
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px 20px; /* 화면 가장자리와 여백 */
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.image-modal.is-active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
width: auto; /* 너비를 자동으로 설정 */
|
||||
max-width: 100%; /* 화면 너비를 넘지 않도록 설정 */
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,.5);
|
||||
animation: modal-slide-down 0.4s ease-out;
|
||||
display: flex; /* 내부 요소 정렬을 위해 flex 사용 */
|
||||
flex-direction: column; /* 이미지와 텍스트를 세로로 쌓음 */
|
||||
}
|
||||
|
||||
@keyframes modal-slide-down {
|
||||
from {
|
||||
transform: translateY(-50px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content .modal-image {
|
||||
display: block;
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
object-fit: contain;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.modal-info {
|
||||
padding: 20px 25px;
|
||||
max-width: 800px; /* 텍스트 영역의 최대 너비는 제한 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-info .modal-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.modal-info .modal-desc {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
font-size: 35px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.5);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.close-btn:hover,
|
||||
.close-btn:focus {
|
||||
color: #ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
/* --- 11. [개선] 가독성 향상을 위한 줄바꿈 처리 --- */
|
||||
.section-header h2,
|
||||
.section-header p,
|
||||
.product-info-trend h3,
|
||||
.product-info-trend p,
|
||||
.item-info h3,
|
||||
.item-info p {
|
||||
word-break: keep-all;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
/* --- 12. [개선] 카드 설명 텍스트 잘림 방지 및 높이 고정 --- */
|
||||
.product-info-trend p,
|
||||
.item-info p {
|
||||
height: 3.04rem;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* --- 13. [최종 수정] 모듈 스크롤바 완전 숨김 처리 --- */
|
||||
/* 1. 기본 상태: 스크롤바를 완전히 투명하게 만듭니다. */
|
||||
.image-modal {
|
||||
/* Firefox: 스크롤바 색상을 양쪽 모두 투명하게 설정 */
|
||||
scrollbar-color: transparent transparent;
|
||||
scrollbar-width: thin;
|
||||
transition: scrollbar-color 0.3s ease;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.image-modal::-webkit-scrollbar-thumb {
|
||||
/* Webkit: 스크롤바 막대를 투명하게 */
|
||||
background-color: transparent;
|
||||
border-radius: 10px;
|
||||
border: 3px solid transparent;
|
||||
background-clip: padding-box;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* 2. :hover 상태: 마우스를 올리면 스크롤바가 나타납니다. */
|
||||
.image-modal:hover {
|
||||
/* Firefox: 스크롤바 색상을 보이게 변경 */
|
||||
scrollbar-color: rgba(0, 0, 0, 0.4) transparent;
|
||||
}
|
||||
|
||||
.image-modal:hover::-webkit-scrollbar-thumb {
|
||||
/* Webkit: 스크롤바 막대 색상을 보이게 변경 */
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// 💡 [핵심 수정] 모든 로직을 초기화 함수 안으로 옮기고, 모듈의 고유 ID를 인자로 받도록 변경합니다.
|
||||
function initProductsSectionModule(moduleId) {
|
||||
// 💡 [핵심 수정] document가 아닌, 전달받은 moduleId를 기준으로 요소를 찾습니다.
|
||||
const moduleElement = document.getElementById(moduleId);
|
||||
if (!moduleElement) return;
|
||||
|
||||
// 이미 초기화된 모듈은 다시 실행하지 않습니다.
|
||||
if (moduleElement.classList.contains('initialized')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const section = moduleElement.querySelector('.products-trend-section');
|
||||
const productGrid = moduleElement.querySelector('.product-grid');
|
||||
const modal = moduleElement.querySelector('.image-modal');
|
||||
|
||||
if (!section || !productGrid || !modal) {
|
||||
console.error('Module elements not found in:', moduleId);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 그리드에 제품 카드를 렌더링하는 함수
|
||||
*/
|
||||
function renderGrid() {
|
||||
const productsJson = section.dataset.products;
|
||||
let productsData;
|
||||
|
||||
try {
|
||||
productsData = JSON.parse(productsJson);
|
||||
} catch (e) {
|
||||
productGrid.innerHTML = '<p style="text-align:center; padding: 40px 0; color: #d9534f;">제품 데이터를 불러오는 데 실패했습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!productsData || productsData.length === 0) {
|
||||
productGrid.innerHTML = '<p style="text-align:center; padding: 40px 0; color: #888;">표시할 제품이 없습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const productCardsHTML = productsData.map(item => `
|
||||
<div class="product-card-trend js-modal-trigger" data-title="${item.title}" data-desc="${item.description}" data-img="${item.image}">
|
||||
<div class="product-image-trend">
|
||||
<img src="${item.image}" alt="${item.title}">
|
||||
</div>
|
||||
<div class="product-info-trend">
|
||||
<h3>${item.title}</h3>
|
||||
<p>${item.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
productGrid.innerHTML = productCardsHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* 모달 관련 이벤트를 설정하는 함수
|
||||
*/
|
||||
function setupModalEvents() {
|
||||
const modalImage = modal.querySelector('.modal-image');
|
||||
const modalTitle = modal.querySelector('.modal-title');
|
||||
const modalDesc = modal.querySelector('.modal-desc');
|
||||
const closeBtn = modal.querySelector('.close-btn');
|
||||
|
||||
// 모달 열기 (이벤트 위임)
|
||||
productGrid.addEventListener('click', function(event) {
|
||||
const card = event.target.closest('.js-modal-trigger');
|
||||
if (card) {
|
||||
modalImage.src = card.dataset.img;
|
||||
modalTitle.textContent = card.dataset.title;
|
||||
modalDesc.textContent = card.dataset.desc;
|
||||
modal.classList.add('is-active');
|
||||
}
|
||||
});
|
||||
|
||||
// 모달 닫기 함수
|
||||
function closeModal() {
|
||||
modal.classList.remove('is-active');
|
||||
}
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
modal.addEventListener('click', function(event) {
|
||||
if (event.target === modal) closeModal();
|
||||
});
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape' && modal.classList.contains('is-active')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 함수 실행
|
||||
renderGrid();
|
||||
setupModalEvents();
|
||||
|
||||
// 초기화 완료 클래스 추가
|
||||
moduleElement.classList.add('initialized');
|
||||
}
|
||||
|
||||
// 💡 [핵심 수정] 다른 곳에서 이 함수를 다시 호출할 수 있도록 전역에 노출시킵니다.
|
||||
window.initProductsSectionModule = initProductsSectionModule;
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// --- 데이터 처리 ---
|
||||
$products_data = array();
|
||||
$sql = " SELECT wr_id, wr_subject, wr_content FROM {$g5['write_prefix']}products WHERE wr_is_comment = 0 ORDER BY wr_num, wr_reply LIMIT 3 ";
|
||||
$result = sql_query($sql);
|
||||
|
||||
for ($i=0; $row=sql_fetch_array($result); $i++) {
|
||||
$files = get_file('products', $row['wr_id']);
|
||||
$image_url = (isset($files[0]['path']) && isset($files[0]['file'])) ? $files[0]['path'].'/'.$files[0]['file'] : G5_THEME_URL.'/img/no_image.png';
|
||||
|
||||
$products_data[] = array(
|
||||
'id' => $row['wr_id'],
|
||||
'title' => get_text($row['wr_subject']),
|
||||
'description' => get_text(cut_str(strip_tags($row['wr_content']), 100)),
|
||||
'image' => $image_url
|
||||
);
|
||||
}
|
||||
$products_json = json_encode($products_data, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// CSS와 JS 파일의 버전을 파일 수정 시간으로 자동 갱신
|
||||
$module_css_path = G5_THEME_PATH.'/rb.custom/products_section/module.css';
|
||||
$module_js_path = G5_THEME_PATH.'/rb.custom/products_section/module.js';
|
||||
$module_css_ver = file_exists($module_css_path) ? filemtime($module_css_path) : G5_CSS_VER;
|
||||
$module_js_ver = file_exists($module_js_path) ? filemtime($module_js_path) : G5_JS_VER;
|
||||
|
||||
// 💡 [핵심] 이 모듈만의 고유 ID를 생성합니다.
|
||||
$module_id = 'products_section_'.uniqid();
|
||||
?>
|
||||
|
||||
<!-- 💡 [핵심 수정] 모듈의 가장 바깥 요소에 고유 ID를 부여합니다. -->
|
||||
<div id="<?php echo $module_id; ?>" class="products-section-module">
|
||||
<section class="products-trend-section" data-products='<?php echo htmlspecialchars($products_json, ENT_QUOTES, 'UTF-8'); ?>'>
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<span class="subtitle">Premium Door</span>
|
||||
<h2>혁신과 기술로 빚어낸 프리미엄 중문</h2>
|
||||
<p>성진미도어는 단순한 중문을 넘어, 공간에 새로운 가치를 더하는 혁신적인 문화를 만들어갑니다.</p>
|
||||
</div>
|
||||
<div class="product-grid">
|
||||
<!-- JS will generate product cards here -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 💡 [핵심 수정] 모듈 내부에 모달 HTML을 포함시킵니다. -->
|
||||
<div class="image-modal">
|
||||
<div class="modal-content">
|
||||
<span class="close-btn">×</span>
|
||||
<img class="modal-image" src="" alt="제품 이미지">
|
||||
<div class="modal-info">
|
||||
<h3 class="modal-title"></h3>
|
||||
<p class="modal-desc"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 모듈에 필요한 CSS 파일을 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/products_section/module.css?ver=<?php echo $module_css_ver; ?>">
|
||||
|
||||
<?php // AJAX로 로드될 때도 스크립트가 확실하게 실행되도록 동적 로딩 방식으로 변경합니다. ?>
|
||||
<script>
|
||||
(function() {
|
||||
// 💡 [핵심 수정] 이 모듈의 고유 ID를 자바스크립트로 전달합니다.
|
||||
const currentModuleId = '<?php echo $module_id; ?>';
|
||||
const scriptId = 'products-section-module-script';
|
||||
|
||||
// 스크립트가 이미 로드되었는지 확인 (중복 실행 방지)
|
||||
if (document.getElementById(scriptId)) {
|
||||
// 이미 로드되었다면, 초기화 함수만 다시 호출
|
||||
if (typeof window.initProductsSectionModule === 'function') {
|
||||
window.initProductsSectionModule(currentModuleId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.src = '<?php echo G5_THEME_URL; ?>/rb.custom/products_section/module.js?ver=<?php echo $module_js_ver; ?>';
|
||||
script.async = true;
|
||||
|
||||
// 💡 [핵심 수정] 스크립트 로드가 완료되면, 고유 ID를 인자로 전달하여 초기화 함수를 호출합니다.
|
||||
script.onload = () => {
|
||||
if (typeof window.initProductsSectionModule === 'function') {
|
||||
window.initProductsSectionModule(currentModuleId);
|
||||
}
|
||||
};
|
||||
|
||||
script.onerror = () => {
|
||||
console.error('Failed to load products_section/module.js');
|
||||
};
|
||||
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,358 @@
|
||||
@charset "utf-8";
|
||||
|
||||
/* ==========================================================================
|
||||
서브 페이지 공통 레이아웃 (subpage common layout)
|
||||
========================================================================== */
|
||||
|
||||
/* --- 상단 비주얼 (Top Visual) --- */
|
||||
.sub-visual {
|
||||
position: relative;
|
||||
height: 250px;
|
||||
background-size: cover;
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
color: #fff;
|
||||
}
|
||||
/* 각 페이지별 배경 이미지 설정 (경로는 테마에 맞게 수정해주세요) */
|
||||
.sub-visual.bg1 { background-image: url('../../../img/sub/sub/visual_bg_01.jpg'); } /* Hi창호는? */
|
||||
.sub-visual.bg2 { background-image: url('../img/sub/visual_bg_02.jpg'); } /* Hi 고객스토리 */
|
||||
|
||||
.sub-visual .inner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sub-visual .inner h2 {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* --- 로컬 네비게이션 (LNB) --- */
|
||||
.lnb-wrap {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #ddd;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.lnb {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.lnb .swiper-wrapper {
|
||||
display: flex;
|
||||
justify-content: center; /* PC에서는 중앙 정렬 */
|
||||
}
|
||||
|
||||
.lnb .swiper-slide {
|
||||
flex-shrink: 0; /* 모바일 스와이프를 위해 축소 방지 */
|
||||
width: auto; /* 내용에 맞게 너비 자동 조절 */
|
||||
}
|
||||
|
||||
.lnb .swiper-slide a {
|
||||
display: block;
|
||||
padding: 18px 30px;
|
||||
font-size: 17px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
transition: color 0.3s;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.lnb .swiper-slide.active a,
|
||||
.lnb .swiper-slide a:hover {
|
||||
color: #1c6a2f; /* 활성/호버 시 색상 */
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.lnb .swiper-slide.active a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: #1c6a2f; /* 활성 메뉴 하단 바 */
|
||||
}
|
||||
|
||||
/* --- 메인 콘텐츠 영역 (Main Contents Area) --- */
|
||||
#container {
|
||||
padding: 80px 20px; /* 상하, 좌우 여백 */
|
||||
}
|
||||
|
||||
#contArea {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.sub-title h2 {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
콘텐츠 스타일 (Contents Style)
|
||||
========================================================================== */
|
||||
.greetings .heading {
|
||||
|
||||
}
|
||||
/* --- 소개 페이지 (greetings) --- */
|
||||
.greetings .heading {
|
||||
position: relative;
|
||||
height: 350px;
|
||||
padding: 50px;
|
||||
margin-bottom: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
background-image: linear-gradient(to right, #2e67a7, #55a13f);
|
||||
}
|
||||
|
||||
.greetings .heading .img img {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 108px;
|
||||
}
|
||||
|
||||
.greetings .heading .txt {
|
||||
position: relative;
|
||||
margin-left: 440px;
|
||||
}
|
||||
|
||||
.greetings .heading .txt .t2 {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.greetings .content {
|
||||
font-size: 16px;
|
||||
line-height: 1.8;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.greetings .content p {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.greetings .content .lg-txt {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.greetings .content .text-green {
|
||||
color: #1c6a2f;
|
||||
}
|
||||
|
||||
/* --- 페이지 이동 링크 (doc-cnt) --- */
|
||||
.doc-cnt {
|
||||
margin-top: 80px;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.link-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.link-group .col a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.link-group .col a:hover {
|
||||
color: #1c6a2f;
|
||||
}
|
||||
|
||||
.link-group .col a i {
|
||||
font-size: 20px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
/* --- 아이콘 리스트 (sub01_3.php) --- */
|
||||
.icon-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon-list li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.icon-list i {
|
||||
margin-right: 10px;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.5;
|
||||
color: #1c6a2f; /* 아이콘 색상 */
|
||||
}
|
||||
|
||||
.icon-list .text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* --- 견적 폼 (sub02.php) --- */
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.form-group:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 1em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-group .options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-group .options label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 20px;
|
||||
padding: 8px 15px;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-group .options input[type="radio"],
|
||||
.form-group .options input[type="checkbox"] {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.form-group .sub-text {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.well3 {
|
||||
border: 1px solid #ddd;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* --- 버튼 스타일 --- */
|
||||
.btn-group {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.btn-group button {
|
||||
padding: 12px 30px;
|
||||
font-size: 16px;
|
||||
margin: 0 10px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.btn-group button[type="submit"] {
|
||||
background-color: #1c6a2f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-group button[type="button"] {
|
||||
background-color: #666;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-group button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
반응형 스타일 (Responsive Style)
|
||||
========================================================================== */
|
||||
@media screen and (max-width: 992px) {
|
||||
.sub-visual .inner h2 {
|
||||
font-size: 32px;
|
||||
}
|
||||
.sub-title h2 {
|
||||
font-size: 28px;
|
||||
}
|
||||
#container {
|
||||
padding: 60px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.sub-visual {
|
||||
height: 200px;
|
||||
}
|
||||
.sub-visual .inner h2 {
|
||||
font-size: 28px;
|
||||
}
|
||||
.lnb .swiper-wrapper {
|
||||
justify-content: flex-start; /* 모바일에서는 왼쪽부터 정렬 */
|
||||
}
|
||||
.lnb .swiper-slide a {
|
||||
padding: 15px 20px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.greetings .heading .txt .t2 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.link-group {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
.link-group .col {
|
||||
text-align: center;
|
||||
}
|
||||
.form-group .options {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
//if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
|
||||
// 레이아웃 폴더내 style.css 파일
|
||||
|
||||
include_once '../../../../common.php';
|
||||
|
||||
// 2. 💡 [핵심] 우리가 만든 서브페이지 전용 CSS 파일을 동적으로 불러옵니다.
|
||||
// 이 코드는 반드시 head.php를 포함하기 전에 위치해야 합니다.
|
||||
//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.custom/submenu/css/subpage.css?ver='.G5_SERVER_TIME.'">', 0);
|
||||
include_once(G5_THEME_PATH.'/head.php');
|
||||
?>
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>Hi창호는?</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<div class="greetings">
|
||||
|
||||
<!-- 💡 [삭제] <style> 태그는 subpage.css 파일로 통합되었으므로 삭제합니다. -->
|
||||
|
||||
<!-- *** 모바일 *** -->
|
||||
<?php if (is_mobile()) { ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<!-- 💡 [수정] 이미지 경로를 테마 URL 기준으로 변경합니다. -->
|
||||
<center><img src="<?php echo G5_THEME_URL; ?>/img/sub/sub/ksj.jpg" alt="Hi창호 소개 이미지"></center>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<p class="t2">
|
||||
<center>Hi 창호는 창호 교체를 쉽고 빠르게 도와주는 플랫폼입니다.<br>
|
||||
한 번에 여러 브랜드 견적을 비교하고 최적의 선택이 가능합니다.<br>
|
||||
제작부터 시공까지 믿을 수 있는 원스톱 서비스를 제공합니다.
|
||||
</center>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- *** PC *** -->
|
||||
<?php if (!is_mobile()) { ?>
|
||||
<div class="heading">
|
||||
<div class="img"><img src="<?php echo G5_THEME_URL; ?>/img/sub/sub/ksj.jpg" alt="Hi창호 소개 이미지"></div>
|
||||
<div class="txt">
|
||||
<p class="t2">Hi 창호는 창호 교체를 쉽고 빠르게 도와주는 플랫폼입니다.<br>
|
||||
한 번에 여러 브랜드 견적을 비교하고 최적의 선택이 가능합니다.<br>
|
||||
제작부터 시공까지 믿을 수 있는 원스톱 서비스를 제공합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="content">
|
||||
<p>안녕하세요, Hi 창호입니다.<br>
|
||||
고객의 삶의 질을 높이는 창호 교체, 이제 Hi 창호와 함께 새롭게 경험해보세요.</p>
|
||||
|
||||
<p>Hi 창호는 아파트, 연립주택, 빌라, 전원주택 등 다양한 주거 형태에 맞춘 창호 교체를 전문적으로 지원하는 토탈 플랫폼입니다.<br>
|
||||
기존의 복잡하고 번거로운 견적 요청 과정을 획기적으로 개선하여, 단 한 번의 정보 입력만으로 여러 브랜드의 견적을 손쉽게 비교하고, 고객에게 가장 합리적인 선택지를
|
||||
제안합니다.</p>
|
||||
|
||||
<p>저희는 창호 제작 공장에서 제품을 직접 배송하고, 숙련된 전문 시공팀이 정확하고 깔끔하게 설치까지 책임지는 <strong>원스톱 서비스</strong>를 제공합니다.<br>
|
||||
단순한 교체를 넘어, 고객의 주거 환경과 예산, 취향을 반영한 <strong>맞춤형 솔루션</strong>을 통해 차별화된 품질과 만족을 약속드립니다.</p>
|
||||
|
||||
<p>Hi 창호는 투명한 가격, 고품질 제품, 그리고 믿을 수 있는 시공으로 고객 한 분 한 분의 소중한 공간을 더욱 가치 있게
|
||||
만듭니다.<br>
|
||||
편리함과 신뢰, 그리고 완성도 높은 결과까지. 창호 교체의 새로운 기준, Hi 창호가 만들어갑니다.</p>
|
||||
|
||||
<p>감사합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
include_once(G5_THEME_PATH . '/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg1">
|
||||
<div class="inner">
|
||||
<h2>Hi창호</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide"><a href="/sub01.php">Hi창호는?</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub01_2.php">Hi창호 차별화 서비스</a></li>
|
||||
<li class="swiper-slide "><a href="/sub01_3.php">창호전문상담가</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>Hi창호 차별화 서비스</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
<!-- *** 모바일 ------------------------------------------------------------------------>
|
||||
<?php if(is_mobile()){ ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-6"><center><img src="/theme/rd.lwd/img/sub/sub/ksjj.jpg" alt=""></center></div>
|
||||
<div class="col-lg-6 col-sm-6"><p class="t2"><center>수 십개 창호 브랜드 견적, 방문 견적서비스<br>
|
||||
직영 시공체재</center></p></div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- *** PC ---------------------------------------------------------------------------->
|
||||
<?php if(!is_mobile()){ ?>
|
||||
<div class="heading">
|
||||
<div class="img"><img src="/theme/rd.lwd/img/sub/sub/ksjj.jpg" alt=""></div>
|
||||
<div class="txt">
|
||||
<!-- <p class="t1">The best choice, the best reward</p> -->
|
||||
<p class="t2">수 십개 창호 브랜드 견적, 방문 견적서비스<br>
|
||||
직영 시공체재</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<!-- //pc ------------------------------------------------------------------------------>
|
||||
|
||||
|
||||
|
||||
<div class="content">
|
||||
<p class="lg-txt"><strong class="text-green">Hi 창호 제공서비스 및 차별화1</strong><br>
|
||||
<strong>수 십개 창호 브랜드 견적, 방문 견적서비스</strong></p>
|
||||
|
||||
<p>홈페이지 간단 입력 후 수십개 창호 브랜드 견적<br>
|
||||
국내 존재하는 수십개 브랜드의 견적을 받아보실 수 있습니다.<br>
|
||||
여기에 같은 브랜드에 다른 견적까지 받아 볼 수 있습니다.</p>
|
||||
|
||||
<p>고객이 직접 창호 사양을 입력 후 견적을 받습니다.</p>
|
||||
|
||||
<p>창호 견적 방문 서비스<br>
|
||||
'하이' 창호 ‘창호 전문 상담가’가 집을 방문해 현장 답사 후 정확한 견적을 받을 수 있도록 도와드립니다.<br>
|
||||
단, 방문 상담비는 3만원입니다.</p>
|
||||
|
||||
<p>입력 견적의 경우 실제 창호리모델링 진행 시 금액이 달라질 수 있지만 창호 전문 상담가가 방문해 작성된 견적은 그대로 진행합니다.<br>
|
||||
창호 견적에는 ‘현장 상황’과 ‘실측 사이즈’에 따라 견적이 많이 달라집니다.</p>
|
||||
|
||||
<p>3만원으로 시간 절약 등 스트레스를 최소화 하세요!!!<br>
|
||||
3만원 견적비는 실제 진행할 경우 2만원을 돌려드립니다.</p>
|
||||
|
||||
<p class="lg-txt"><strong class="text-green">Hi 창호 제공서비스 및 차별화2</strong><br>
|
||||
<strong>직영시공체재</strong></p>
|
||||
|
||||
<p>하이’ 창호는 직영 시공체제를 운영하고 있습니다.<br>
|
||||
또한 창호 제작 노하우를 갖춘 전국의 각 브랜드별 우수 창호 제작업체들을 직접 선정해 창호 제품을 공급하고 있습니다.</p>
|
||||
|
||||
<p>'Hi' 창호는 30년 이상 창호를 연구한 전문인력이 '하이' 창호를 믿고 가성비 좋은 창호 리모델링을 구현해 드립니다.</p>
|
||||
|
||||
<p>'창호' 어려우셨죠! 안심 하시고 저희만 믿고 따라와 주시면 됩니다.</p>
|
||||
|
||||
<p>창호 리모델링에서 창호 제품과 시공이 모두 중요합니다. 즉 50%인 제작과 50%인 시공으로 이뤄져 있습니다.<br>
|
||||
어느 한 쪽도 무시할 순 없지만 제작은 기계의 힘을 빌리지만 시공은 오로지 사람에 의존하기 때문에 시공에 무게를 두는 것이 맞습니다.<br>
|
||||
이에 저희 'Hi' 창호는 직영 시공체재를 유지하고 있어 안심하고 믿으셔도 됩니다.</p>
|
||||
|
||||
<p>3만원으로 시간 절약 등 스트레스를 최소화 하세요!!!<br>
|
||||
3만원 견적비는 실제 진행할 경우 2만원을 돌려드립니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<div class="doc-cnt">
|
||||
<div class="link-group">
|
||||
<div class="col">
|
||||
<a href="/sub01_3.php"><i class="xi-arrow-left"></i> <strong>창호 전문 상담가 바로가기</strong></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/sub02.php"><strong>창호견적 바로가기</strong> <i class="xi-arrow-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg1">
|
||||
<div class="inner">
|
||||
<h2>Hi창호</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide"><a href="/sub01.php">Hi창호는?</a></li>
|
||||
<li class="swiper-slide"><a href="/sub01_2.php">Hi창호 차별화 서비스</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub01_3.php">창호전문상담가</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>창호전문상담가</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
<!-- *** 모바일 ------------------------------------------------------------------------>
|
||||
<?php if(is_mobile()){ ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-6"><center><img src="/theme/rd.lwd/img/sub/sub/kssjj.jpg" alt=""></center></div>
|
||||
<div class="col-lg-6 col-sm-6"><p class="t2"><center>'창호 전문 상담가'의 업무는<br>
|
||||
창문에 대한 실측 · 창문 종류 · 유리 · 시공 등 복합적으로 알려드립니다!</center></p></div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- *** PC ---------------------------------------------------------------------------->
|
||||
<?php if(!is_mobile()){ ?>
|
||||
<div class="heading">
|
||||
<div class="img"><img src="/theme/rd.lwd/img/sub/sub/kssjj.jpg" alt=""></div>
|
||||
<div class="txt">
|
||||
<!-- <p class="t1">The best choice, the best reward</p> -->
|
||||
<p class="t2">'창호 전문 상담가'의 업무는<br>
|
||||
창문에 대한 실측 · 창문 종류 · 유리 · 시공 등<br>복합적으로 알려드립니다!</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<!-- //pc ------------------------------------------------------------------------------>
|
||||
|
||||
<style>
|
||||
.icon-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon-list li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.icon-list i {
|
||||
margin-right: 10px;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.icon-list .text {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="content">
|
||||
<!-- 01 -->
|
||||
<ul class="icon-list">
|
||||
<li>
|
||||
<i class="xi-view-list"></i>
|
||||
<div class="text">
|
||||
<font color="#000000">상담자가 어떤 일을 하는지, 그리고 상담받을 때 어떤 점을 확인해야 하는지 쉽게 설명해 드릴게요! <br>
|
||||
‘창호 전문 상담가’는 우선 견적과 실제 시공 간의 편차를 줄여줍니다.<br>
|
||||
현장을 방문해 실측해서 정확한 금액을 산출하기 위함입니다.</font>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<i class="xi-view-list"></i>
|
||||
<div class="text">
|
||||
<font color="#000000">창문에 대한 궁금한 사항, 창문 설치 과정, 시공 등의 정보를 친절히 알려드리고, 창문 설치가 안전하고 정확하게 이루어지도록 도와드려요. <br>
|
||||
실측(정확한 치수 측정)부터 시공 일정 안내, 창문 교체 후 주의사항까지 모두 책임지고 안내해 드려요.</font>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- //01 -->
|
||||
|
||||
<p> </p>
|
||||
<p><font color="#3366cc"><strong>1. 상담 전 – 사전 예약 및 방문 준비</strong></font>
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</p>
|
||||
|
||||
<p><i class="xi-check-square"></i> <strong>주부님</strong> : 창호 상담을 받고 싶은데, 어떻게 예약해야 하나요?<br>
|
||||
<i class="xi-check-square"></i> <strong><font color="#ff6600">Hi창호</font></strong><br>
|
||||
먼저 ‘Hi창호’ 홈페이지 방문 후 ‘방문 상담 예약’을 하세요.<br>그럼 ‘창호 전문 상담가’가 지정되어 고객님께 연락을 합니다.<br>
|
||||
방문할 때는 단정한 복장으로 찾아 뵙고, 정확한 상담을 진행할 준비를 합니다.</p>
|
||||
|
||||
<p><i class="xi-view-list"></i> <font color="#000000">상담 전 미리 확인하는 것</font><br>
|
||||
- 가족분들의 일정도 고려하여 편한 시간을 선택하세요.
|
||||
</p>
|
||||
|
||||
<p><i class="xi-key"></i> <strong>주부님 TIP!</strong><br>
|
||||
- 상담을 받기 전에 "현재 창문의 문제점"을 미리 정리해두면 상담이 훨씬 수월해요!</p>
|
||||
|
||||
<p> </p>
|
||||
<p><font color="#3366cc"><strong>2. 창호 실측 – 정확한 치수를 확인하는 과정!</strong></font>
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</p>
|
||||
<p><i class="xi-check-square"></i> <strong>주부님</strong> : 창호 실측이 왜 중요한가요?<br>
|
||||
<i class="xi-check-square"></i> <strong><font color="#ff6600">Hi창호</font></strong><br>
|
||||
실측이 잘못되면 창문이 틀에 맞지 않아 설치가 어려울 수 있어요. 그럼 창호를 다시 제작해야 합니다.<br>비용이 2배 발생합니다. 그래서 창문의 위치, 벽 두께, 유리 종류, 방충망 여부까지 꼼꼼하게 체크해야 해요.</p>
|
||||
|
||||
<p><i class="xi-view-list"></i> <font color="#000000">실측할 때 확인하는 것</font><br>
|
||||
- 교체할 창문의 위치 확인<br>
|
||||
- 창문이 들어갈 공간(개구부)의 가로•세로 길이 측정<br>
|
||||
- 벽 두께, 가스 배관•연통 위치 확인<br>
|
||||
- 창문 개폐 방향(오른쪽 or 왼쪽) 체크<br>
|
||||
- 유리 사양(단열 유리, 방음 유리 등) 및 방충망 유무 확인<br>
|
||||
</p>
|
||||
|
||||
<p><i class="xi-key"></i> <strong>주부님 TIP!</strong><br>
|
||||
- 상담할 때 ‘내가 원하는 창’ 또는 ‘우리집에 필요한 창문’을 검색 등을 통해해 미리 생각해보시면 더 정확한 상담을 받을 수 있어요!</p>
|
||||
|
||||
<p> </p>
|
||||
<p><font color="#3366cc"><strong>3. 현장 점검 – 시공할 때 문제가 없는지 미리 체크!</strong></font>
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</p>
|
||||
<p><i class="xi-check-square"></i> <strong>주부님</strong> : 시공할 때 예상하지 못한 문제가 생기진 않을까요?<br>
|
||||
<i class="xi-check-square"></i> <strong><font color="#ff6600">Hi창호</font></strong><br>
|
||||
그런 일이 없도록 미리 현장을 점검해요.<br>
|
||||
특히 <strong>가구나 세탁기 같은 가전제품과 창문의 간섭 여부</strong>를 체크하는 게 중요해요!</p>
|
||||
|
||||
<p><i class="xi-view-list"></i> <font color="#000000">미리 체크하는 것</font><br>
|
||||
- 사다리차가 필요한지(고층일 경우)<br>
|
||||
- 거주 중인 집인지, 공사 중인 집인지<br>
|
||||
- 세탁기, 장롱 등 가구 간섭 여부<br>
|
||||
- 세탁기가 타워형이라면 AS기사 방문이 필요한지 안내<br>
|
||||
- 시공 일정이 잡히면 관리사무실·경비실에 공사 일정 통보<br>
|
||||
</p>
|
||||
|
||||
<p><i class="xi-key"></i> <strong>주부님 TIP!</strong><br>
|
||||
- "우리 집 창문이 어떤 구조인지, 가구 배치가 창문과 겹치는 부분이 있는지" 미리 확인해 보시면 좋아요!</p>
|
||||
|
||||
<p> </p>
|
||||
<p><font color="#3366cc"><strong>4. 창호 견적 진행 </strong></font>
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</p>
|
||||
<p><i class="xi-check-square"></i> <strong>주부님</strong> : 실측 후 창호리모델링 견적을 주시는 건가요?<br>
|
||||
<i class="xi-check-square"></i> <strong><font color="#ff6600">Hi창호</font></strong><br>
|
||||
상담이 끝나면, ‘창호 전문 상담가’가 견적서를 만들어서 고객님께 전달 또는 홈페이지에서 확인이 가능합니다. 이때 견적서는 다양한 브랜드로 여러 개의 견적서를 받아 보실 수 있습니다. 여기에 같은 브랜드에 다른 견적도 받아 보실 수 있습니다. 이후에 창호리모델링을 결정하시면 창호 제작 및 시공이 진행됩니다.<br>
|
||||
시공을 진행하기로 결정하셨다면, 창호 제작 기간과 설치 날짜를 안내해 드릴 거예요.</p>
|
||||
|
||||
<p><i class="xi-view-list"></i> <font color="#000000">시공을 결정하셨다면 주부님이 준비할 것</font><br>
|
||||
- 창문 주변 물건을 미리 치워두면 더 빠르고 안전한 시공이 가능해요<br>
|
||||
- 시공 당일 먼지가 날릴 수 있으니, 예민한 물건(옷, 침구류 등)은 덮어두는 것도 좋아요.<br>
|
||||
- 공사일에 관리사무소에서 공사 일정 승인이 필요한 경우, 미리 확인해 주세요.<br>
|
||||
</p>
|
||||
|
||||
<p><i class="xi-key"></i> <strong>주부님 TIP!</strong><br>
|
||||
- 공사일에 집에 계시는 게 가장 좋아요! 혹시 일정이 안 맞는다면 가족분께 맡겨주셔도 됩니다.</p>
|
||||
|
||||
<p> </p>
|
||||
<p><font color="#3366cc"><strong>5. 창문 설치 후, 마무리 및 A/S 안내</strong></font>
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</p>
|
||||
<p><i class="xi-check-square"></i> <strong>주부님</strong> : 창문 시공이 끝난 후에는 어떤 일정이 남아 있나요?<br>
|
||||
<i class="xi-check-square"></i> <strong><font color="#ff6600">Hi창호</font></strong><br>
|
||||
네! 창문이 제대로 설치되었는지 ‘창호 전문 시공자’와 함께 꼭 확인하셔야 해요. 우선 시공 당일에 시공 완료에 대한 여러가지 사항을 고객님과 함께 체크해 드립니다. 이후에 궁금한 점이 있다면 홈페이지 문의를 통해 글로 답변이 기본 원칙이고 필요에 따라 전화나 방문을 진행합니다.</p>
|
||||
|
||||
<p><i class="xi-view-list"></i> <font color="#000000">설치 후 확인할 것</font><br>
|
||||
- 창문이 부드럽게 열리고 닫히는지 확인하기<br>
|
||||
- 틈새 없이 밀착되었는지 체크하기<br>
|
||||
- 손잡이, 잠금장치가 정상적으로 작동하는지 테스트하기<br>
|
||||
- A/S(사후 서비스) 기간과 보증 범위 확인하기
|
||||
</p>
|
||||
|
||||
<p><i class="xi-key"></i> <strong>주부님 TIP!</strong><br>
|
||||
- 창문 설치 후 이상이 있으면 바로 이야기해주세요! 사소한 문제도 바로 해결하는 게 중요해요.</p>
|
||||
|
||||
<p><i class="xi-check-square"></i> <strong>창호 상담자를 통해 더 안전하고 편리한 창문 교체를!</strong><br>
|
||||
- 창문 교체를 고민하고 계신다면, 창호 상담자와 충분히 상담해보세요!<br>
|
||||
- 단순히 창문을 교체하는 게 아니라, 우리 집에 딱 맞는 창문을 찾고 안전하게 설치하는 과정이에요.</p>
|
||||
|
||||
<p><i class="xi-check-square"></i> <strong>궁금한 점이 있다면 언제든지 문의하세요! </strong></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<!-- <div class="doc-cnt">
|
||||
<div class="link-group">
|
||||
<div class="col">
|
||||
<a href="/sub01_3.php"><i class="xi-arrow-left"></i> <strong>창호 전문 상담가 바로가기</strong></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/sub02.php"><strong>창호견적 바로가기</strong> <i class="xi-arrow-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
if (!defined('_INDEX_')) define('_INDEX_', true);
|
||||
//if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
// 1. 그누보드 공통 파일을 포함하여 기본 설정을 불러옵니다.
|
||||
include_once '../../../../common.php';
|
||||
|
||||
// 2. 💡 [핵심] 우리가 만든 서브페이지 전용 CSS 파일을 동적으로 불러옵니다.
|
||||
// 이 코드는 반드시 head.php를 포함하기 전에 위치해야 합니다.
|
||||
add_stylesheet('<link rel="stylesheet" href="'.G5_THEME_URL.'/rb.custom/submenu/css/subpage.css?ver='.G5_SERVER_TIME.'">', 0);
|
||||
|
||||
// 3. 💡 [핵심] 그누보드 원본 head.php 대신, 현재 '적용된 테마'의 head.php를 불러옵니다.
|
||||
// 이렇게 해야 사이트의 공통 헤더, 메뉴, 전체 스타일이 적용됩니다.
|
||||
include_once(G5_THEME_PATH.'/head.php');
|
||||
?>
|
||||
<div id="container" class="sub-page">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>Hi창호는?</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<div class="greetings">
|
||||
|
||||
<!-- 💡 [삭제] <style> 태그는 subpage.css 파일로 통합되었으므로 삭제합니다. -->
|
||||
|
||||
<!-- *** 모바일 *** -->
|
||||
<?php if (is_mobile()) { ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<!-- 💡 [수정] 이미지 경로를 테마 URL 기준으로 변경합니다. -->
|
||||
<center><img src="<?php echo G5_THEME_URL; ?>/img/sub/sub/ksj.jpg" alt="Hi창호 소개 이미지"></center>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<p class="t2">
|
||||
<center>Hi 창호는 창호 교체를 쉽고 빠르게 도와주는 플랫폼입니다.<br>
|
||||
한 번에 여러 브랜드 견적을 비교하고 최적의 선택이 가능합니다.<br>
|
||||
제작부터 시공까지 믿을 수 있는 원스톱 서비스를 제공합니다.
|
||||
</center>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- *** PC *** -->
|
||||
<?php if (!is_mobile()) { ?>
|
||||
<div class="heading">
|
||||
<div class="img"><img src="<?php echo G5_THEME_URL; ?>/img/sub/sub/ksj.jpg" alt="Hi창호 소개 이미지"></div>
|
||||
<div class="txt">
|
||||
<p class="t2">Hi 창호는 창호 교체를 쉽고 빠르게 도와주는 플랫폼입니다.<br>
|
||||
한 번에 여러 브랜드 견적을 비교하고 최적의 선택이 가능합니다.<br>
|
||||
제작부터 시공까지 믿을 수 있는 원스톱 서비스를 제공합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="content">
|
||||
<p>안녕하세요, Hi 창호입니다.<br>
|
||||
고객의 삶의 질을 높이는 창호 교체, 이제 Hi 창호와 함께 새롭게 경험해보세요.</p>
|
||||
|
||||
<p>Hi 창호는 아파트, 연립주택, 빌라, 전원주택 등 다양한 주거 형태에 맞춘 창호 교체를 전문적으로 지원하는 토탈 플랫폼입니다.<br>
|
||||
기존의 복잡하고 번거로운 견적 요청 과정을 획기적으로 개선하여, 단 한 번의 정보 입력만으로 여러 브랜드의 견적을 손쉽게 비교하고, 고객에게 가장 합리적인 선택지를
|
||||
제안합니다.</p>
|
||||
|
||||
<p>저희는 창호 제작 공장에서 제품을 직접 배송하고, 숙련된 전문 시공팀이 정확하고 깔끔하게 설치까지 책임지는 <strong>원스톱 서비스</strong>를 제공합니다.<br>
|
||||
단순한 교체를 넘어, 고객의 주거 환경과 예산, 취향을 반영한 <strong>맞춤형 솔루션</strong>을 통해 차별화된 품질과 만족을 약속드립니다.</p>
|
||||
|
||||
<p>Hi 창호는 투명한 가격, 고품질 제품, 그리고 믿을 수 있는 시공으로 고객 한 분 한 분의 소중한 공간을 더욱 가치 있게
|
||||
만듭니다.<br>
|
||||
편리함과 신뢰, 그리고 완성도 높은 결과까지. 창호 교체의 새로운 기준, Hi 창호가 만들어갑니다.</p>
|
||||
|
||||
<p>감사합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<?php
|
||||
include_once(G5_THEME_PATH.'/tail.php');
|
||||
@@ -0,0 +1,874 @@
|
||||
<script>location.href = '/bbs/board.php?bo_table=order';</script>
|
||||
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH . '/thumbnail.lib.php';
|
||||
include_once G5_PATH . '/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg2">
|
||||
<div class="inner">
|
||||
<h2>Hi 고객스토리</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide active "><a href="/sub02.php">창호견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_1.php">시공견적</a></li>
|
||||
<li class="swiper-slide "><a href="/sub02_2.php">창호소비효율등급제</a></li>
|
||||
<li class="swiper-slide "><a href="/sub02_3.php">창호리모델링시대</a></li>
|
||||
<li class="swiper-slide "><a href="/sub02_4.php">고객이 알아야 할 창호시공 10선</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>창호견적</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width: 992px) {
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<!-- 입력폼 style -->
|
||||
<style>
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 0px solid #eee;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 1em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.options label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 20px;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.options input[type="radio"] {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.sub-text {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.image-box {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.image-box img {
|
||||
width: 150px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.input-inline {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.placeholder-input {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.options,
|
||||
.image-box,
|
||||
.input-inline {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
appearance: none; /* 브라우저 기본 체크박스 제거 */
|
||||
-webkit-appearance: none;
|
||||
border: 3px solid #000000; /* 진한 테두리 */
|
||||
border-radius: 3px;
|
||||
background-color: white;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked::before {
|
||||
content: '✔';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -55%); /* 정확히 중앙으로 이동 */
|
||||
font-size: 16px;
|
||||
color: #990000;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
<!-- //입력폼 style -->
|
||||
|
||||
|
||||
<div class="content">
|
||||
<!-------------------------------- 입력폼 시작 -------------------------------->
|
||||
<form action="/submit" method="post">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="form-group">
|
||||
<label>1. 주소</label>
|
||||
<input type="text" placeholder="주소를 입력하세요">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-2">
|
||||
<div class="form-group">
|
||||
<label>2. 평형</label>
|
||||
<input type="text" placeholder="평형 입력" style="width: 100px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label>3. 집의 형태</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="house-type"> 아파트</label>
|
||||
<label><input type="radio" name="house-type"> 빌라</label>
|
||||
<label><input type="radio" name="house-type"> 신축</label>
|
||||
<label><input type="radio" name="house-type"> 전원주택</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>4. 창 재질</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="material"> PVC(폴리염화비닐)</label>
|
||||
<label><input type="radio" name="material"> AL(알루미늄)</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 제품선택 --------------------------------->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="well3">
|
||||
<font color="#cc0000"><i class="xi-touch"></i> <strong>5. 아래의 선택은 복수 선택이
|
||||
가능합니다!</strong></font>
|
||||
|
||||
|
||||
<!-- 제품선택영역 -->
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="form-group">
|
||||
<center><img src="../images/sub/sub02_01.jpg" alt=""></center>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#3366cc"><span
|
||||
style="font-size: 21px;">거실 발코니1</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
※ 단창은 창짝이 2개, 이중창은 창짝이 4개<br>
|
||||
※ 분합창 : 거실과 베란다 사이의 문<br>
|
||||
※ 발코니창 : 베란다 외부와 접한 창
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
※ 방충망은 외부에 접한 외창에 기본설치<br>
|
||||
※ 내창은 고객 선택
|
||||
</div>
|
||||
<!-- <div class="sub-text">
|
||||
※ 내창: 외부에 접하지 않은 내부의 창<br>
|
||||
※ 외창: 외부에 접한 창
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#3366cc"><span
|
||||
style="font-size: 21px;">거실 발코니2</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#006600"><span
|
||||
style="font-size: 21px;">안방 발코니1</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#006600"><span
|
||||
style="font-size: 21px;">안방 발코니2</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#ff6600"><span
|
||||
style="font-size: 21px;">뒤베란다 외부창1</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#ff6600"><span
|
||||
style="font-size: 21px;">뒤베란다 외부창2</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#ff6600"><span
|
||||
style="font-size: 21px;">뒤베란다 외부창3</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#990000"><span
|
||||
style="font-size: 21px;">다용도실 외부창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#990000"><span
|
||||
style="font-size: 21px;">다용도실 내부창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">안방 내창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">거실 분합 내창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">주방 터닝도어 내창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">입구방</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">다용도실문 내창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">건너방 분합문 내창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">안방 분합문</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-6">
|
||||
<div class="well2">
|
||||
<div class="form-group">
|
||||
<label><input type="checkbox" name="replace"> <font color="#000000"><span
|
||||
style="font-size: 21px;">주방창</span></font></label>
|
||||
<div class="options">
|
||||
■ 기존창 규격 :
|
||||
<input type="text" placeholder="가로" style="width: 100px;"><span>X</span>
|
||||
<input type="text" placeholder="세로" style="width: 100px;">
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창비율 :
|
||||
<label><input type="radio" name="ratio"> 1 대 1</label>
|
||||
<label><input type="radio" name="ratio"> 1 대 1.5 대 1</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 창호형태 :
|
||||
<label><input type="radio" name="ratio"> 단창</label>
|
||||
<label><input type="radio" name="ratio"> 이중창</label>
|
||||
<label><input type="radio" name="ratio"> 분합창</label>
|
||||
<label><input type="radio" name="ratio"> 발코니창</label>
|
||||
</div>
|
||||
<div class="options">
|
||||
■ 방충망 :
|
||||
<label><input type="radio" name="ratio"> 유</label>
|
||||
<label><input type="radio" name="ratio"> 무</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- //제품선택영역 -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- //제품선택 끝 ----------------------------->
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>6. 창호색상</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="color"> 일반 백색</label>
|
||||
<label><input type="radio" name="color"> 도장(색지정)</label>
|
||||
</div>
|
||||
<div class="sub-text">
|
||||
※ 도장 - 창호는 기본 백색으로 생산하지만 고객이 지정색을 원할 경우 색을 입히는 비용 추가
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>7. 교체부위</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="glass"> 전체</label>
|
||||
<label><input type="radio" name="glass"> 외창</label>
|
||||
<label><input type="radio" name="glass"> 내창</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>8. 핸들사양</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="handle"> 자동</label>
|
||||
<label><input type="radio" name="handle"> 일반</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>9. 유리사양</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="glass"> 로이</label>
|
||||
<label><input type="radio" name="glass"> 일반</label>
|
||||
</div>
|
||||
<div class="sub-text">
|
||||
※ 로이유리 - 일반 유리 표면에 단열 코팅
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>10. 유리색상</label>
|
||||
<div class="options">
|
||||
<label><input type="radio" name="glass-color"> 투명</label>
|
||||
<label><input type="radio" name="glass-color"> 그린</label>
|
||||
<label><input type="radio" name="glass-color"> 미스트(불투명)</label>
|
||||
<input type="text" placeholder="기타" onfocus="this.placeholder=''"
|
||||
onblur="this.placeholder='기타'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="form-group">
|
||||
<label>11. 추가사항</label>
|
||||
<textarea rows="5" placeholder="추가로 필요한 내용을 입력해 주세요"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 버튼 영역 -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div style="margin-top: 20px;">
|
||||
<center>
|
||||
<button type="submit">보내기</button>
|
||||
<button type="button" onclick="history.back();">취소</button>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
button {
|
||||
padding: 12px 30px; /* 높이와 너비 늘림 */
|
||||
font-size: 16px; /* 글자 크기 키움 */
|
||||
margin: 0 10px; /* 버튼 사이 여백 */
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button[type="submit"] {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button[type="button"] {
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
</form>
|
||||
<!-------------------------------- //입력폼 시작 -------------------------------->
|
||||
<p> </p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH . '/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
include_once('./_common.php');
|
||||
|
||||
// 페이지 제목 설정
|
||||
$g5['title'] = '시공견적 안내';
|
||||
|
||||
// 헤더 파일 포함
|
||||
include_once(G5_PATH.'/head.php');
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
|
||||
<div class="sub-visual bg2">
|
||||
<div class="inner">
|
||||
<h2>Hi 고객스토리</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide"><a href="/sub02.php">창호견적</a></li>
|
||||
<li class="swiper-slide active"><a href="/sub02_1.php">시공견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_2.php">창호소비효율등급제</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_3.php">창호리모델링시대</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_4.php">고객이 알아야 할 창호시공 10선</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>시공견적 페이지</h2>
|
||||
</div>
|
||||
|
||||
<div class="real-cont">
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
<style>
|
||||
/* 페이지 전용 스타일 */
|
||||
.estimate-guide-content h3.doc-tit { font-size: 22px; color: #003300; margin-bottom: 20px; }
|
||||
.estimate-guide-content p { margin-bottom: 15px; color: #555; line-height: 1.8; }
|
||||
.variable-list { list-style: none; padding-left: 20px; margin-bottom: 20px; }
|
||||
.variable-list li { position: relative; margin-bottom: 10px; padding-left: 5px; }
|
||||
.variable-list li:before { content: '✓'; position: absolute; left: -20px; color: #3d6cb9; font-weight: bold; }
|
||||
.important-notice { background-color: #fffbe6; border: 1px solid #ffe58f; border-radius: 8px; padding: 15px 20px; color: #8a6d3b; margin-top: 20px; }
|
||||
.important-notice i { margin-right: 10px; }
|
||||
.cost-table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 15px; }
|
||||
.cost-table th, .cost-table td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
||||
.cost-table th { background-color: #f9f9f9; font-weight: bold; }
|
||||
.cost-table td:last-child { text-align: right; font-family: 'Malgun Gothic', sans-serif; }
|
||||
.calculator-box { background-color: #f5faff; border: 1px solid #d6eaff; border-radius: 8px; padding: 25px; margin-top: 20px; }
|
||||
.calculator-box .input-group { display: flex; align-items: center; margin-bottom: 15px; }
|
||||
.calculator-box label { width: 100px; font-weight: bold; }
|
||||
.calculator-box input[type="number"] { flex-grow: 1; padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
|
||||
.calculator-box button { display: block; width: 100%; padding: 12px; background-color: #3d6cb9; color: white; border: none; border-radius: 4px; font-size: 18px; cursor: pointer; transition: background-color 0.2s; }
|
||||
.calculator-box button:hover { background-color: #2c5282; }
|
||||
#result-display { margin-top: 20px; padding: 15px; background-color: #fff; border: 1px solid #ddd; border-radius: 4px; font-size: 18px; text-align: center; }
|
||||
#result-display span { font-weight: bold; color: #d9534f; }
|
||||
|
||||
@media screen and (max-width:992px){
|
||||
.row { display: flex; flex-wrap: wrap; margin: 0 auto; width: 100%; flex-direction: column; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="content estimate-guide-content">
|
||||
<h3 class="doc-tit"><font color="#003300">창호 시공비 안내</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p>
|
||||
고객님이 시공을 의뢰할 경우 참고하는 ‘시공견적페이지’입니다. 이곳에서는 창호 시공 진행과정에 따른 금액 변동을 알 수 있습니다.
|
||||
</p>
|
||||
<p>
|
||||
창호 시공 금액이 변동될 수 있는 항목들을 확인하시고 항목들에 따라서 추가되는 금액을 확인하신 후 ‘창호전문상담가’가 추후에 방문해 다시 자세하게 설명해 드립니다.
|
||||
</p>
|
||||
<p>
|
||||
이곳에서는 창호 틀당 고객님이 직접 시공비를 산출하실 수도 있습니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">창호 시공 시 현장 변동 항목</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p>
|
||||
아래는 창호 시공 시 현장 상황에 따라 시공비가 달라질 수 있는 주요 항목들입니다.
|
||||
</p>
|
||||
<ul class="variable-list">
|
||||
<li>층고에 따른 사다리차 가능 유무 (윈치 작업)</li>
|
||||
<li>하부타일 마감</li>
|
||||
<li>베란다 확장</li>
|
||||
<li>상부장 탈부착 (씽크대)</li>
|
||||
<li>하리(구조물) 절단</li>
|
||||
<li>엘리베이터 사용 여부</li>
|
||||
</ul>
|
||||
<p class="important-notice">
|
||||
<i class="fa fa-exclamation-triangle"></i>
|
||||
위의 현장 상황에 따라서 시공비 편차가 많이 발생할 수 있기 때문에, 실제 시공 시에는 <strong>창호전문상담가의 방문을 원칙</strong>으로 하고 있습니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">주요 추가 비용 항목 (예시)</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<table class="cost-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>항목</th>
|
||||
<th>비용 (VAT 별도)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>스카이 장비</td><td>600,000원</td></tr>
|
||||
<tr><td>사다리차</td><td>300,000원</td></tr>
|
||||
<tr><td>윈치</td><td>300,000원</td></tr>
|
||||
<tr><td>하부타일 마감</td><td>100,000원</td></tr>
|
||||
<tr><td>몰딩 마감</td><td>100,000원</td></tr>
|
||||
<tr><td>철거비 (기본 6틀)</td><td>450,000원</td></tr>
|
||||
<tr><td>추가 철거 (틀당)</td><td>30,000원</td></tr>
|
||||
<tr><td>보양 작업비</td><td>150,000원</td></tr>
|
||||
<tr><td>싱크대 상부장 탈부착</td><td>100,000원</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">창당 시공 단가 간편 산출기</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p>창호의 가로, 세로 사이즈를 입력하여 대략적인 시공 단가를 계산해볼 수 있습니다. (정확한 금액은 전문가 상담이 필요합니다.)</p>
|
||||
<div class="calculator-box">
|
||||
<div class="input-group">
|
||||
<label for="width-input">가로 (mm)</label>
|
||||
<input type="number" id="width-input" placeholder="예: 1800">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="height-input">세로 (mm)</label>
|
||||
<input type="number" id="height-input" placeholder="예: 2100">
|
||||
</div>
|
||||
<button id="calculate-btn">계산하기</button>
|
||||
<div id="result-display">
|
||||
예상 시공 단가: <span>계산 버튼을 눌러주세요.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const calculateBtn = document.getElementById('calculate-btn');
|
||||
const widthInput = document.getElementById('width-input');
|
||||
const heightInput = document.getElementById('height-input');
|
||||
const resultSpan = document.querySelector('#result-display span');
|
||||
|
||||
calculateBtn.addEventListener('click', function() {
|
||||
const width = parseFloat(widthInput.value);
|
||||
const height = parseFloat(heightInput.value);
|
||||
|
||||
if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0) {
|
||||
alert('올바른 가로, 세로 값을 mm 단위로 입력해주세요.');
|
||||
resultSpan.textContent = '계산 오류';
|
||||
return;
|
||||
}
|
||||
|
||||
// 공식: (가로(mm) * 세로(mm) / 1,000,000) * 90,000원
|
||||
const areaInM2 = (width * height) / 1000000;
|
||||
const pricePerM2 = 90000;
|
||||
const estimatedCost = Math.round(areaInM2 * pricePerM2);
|
||||
|
||||
resultSpan.textContent = estimatedCost.toLocaleString('ko-KR') + ' 원';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
// 푸터 파일 포함
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg2">
|
||||
<div class="inner">
|
||||
<h2>Hi 고객스토리</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub02.php">창호견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_1.php">시공견적</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub02_2.php">창호소비효율등급제</a></li>
|
||||
<li class="swiper-slide "><a href="/sub02_3.php">창호리모델링시대</a></li>
|
||||
<li class="swiper-slide "><a href="/sub02_4.php">고객이 알아야 할 창호시공 10선</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>창호 소비 효율 등급제</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<h3 class="doc-tit"><font color="#003300">창호 소비효율 등급제, 왜 중요할까요?</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-5"><center><img class="img-responsive" src="/theme/rd.lwd/img/sub/sub/dn01.jpg" alt=""/></center></div>
|
||||
<div class="col-lg-7">
|
||||
<p>요즘 창호를 교체하려고 하면 **‘소비효율 등급’**이라는 단어를 자주 접하게 됩니다.<br>창호에도 냉장고나 세탁기처럼 에너지 등급이 있다는 사실, 알고 계셨나요?<br>이 등급제는 우리 집의 <strong>난방비 절감과 에너지 절약을 돕기 위해 만들어진 제도</strong>입니다.<br>하지만 처음부터 존재했던 것은 아닙니다.<br>창호 소비효율 등급제는 왜 도입되었으며, 어떤 변화가 있었을까요?</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">창호 소비효율 등급제의 도입 배경</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-7">
|
||||
<p>과거에는 창호의 성능을 평가할 수 있는 객관적인 기준이 없었습니다.<br>
|
||||
소비자들은 단순히 디자인이나 가격을 기준으로 창호를 선택했지만, 사실 창호의 성능 차이는 매우 큽니다. 특히 <strong>열이 잘 새어나가는 창호는 난방비를 증가시키고, 실내 환경을 불안정하게 만드는 원인</strong>이 됩니다.<br>
|
||||
정부는 에너지 절약을 위해 2012년부터 창호에도 <strong>소비효율 등급제</strong>를 도입했습니다.<br>이 제도를 통해 창호의 단열 성능을 1등급부터 5등급까지 나누고, <strong>소비자가 창호를 비교하고 선택할 수 있도록</strong> 했습니다.<br>즉, 성능이 좋은 창호를 쉽게 구별할 수 있도록 만든 것입니다.</p>
|
||||
</div>
|
||||
<div class="col-lg-5"><center><img class="img-responsive" src="/theme/rd.lwd/img/sub/sub/dn02.jpg" alt=""/></center></div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">창호 1등급 기준이 변경된 이유</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-5"><center><img class="img-responsive" src="/theme/rd.lwd/img/sub/sub/dn03.jpg" alt=""/></center></div>
|
||||
<div class="col-lg-7">
|
||||
<p>하지만 시간이 지나면서 건축 기술이 발전하고, 창호의 성능도 점점 향상되었습니다.<br>
|
||||
초기에는 <strong>기준이 낮아</strong> 웬만한 제품이 1등급을 받을 수 있었지만, 이후 <strong>더 엄격한 기준이 필요</strong>해졌습니다.<br>
|
||||
그래서 2023년부터 <strong>1등급 기준이 더욱 강화</strong>되었습니다.<br>과거 1등급이었던 창호가 이제는 2등급이나 3등급으로 내려간 것이죠. 이는 <strong>보다 높은 성능의 창호가 1등급을 받을 수 있도록 기준을 조정한 것</strong>입니다. 이를 통해 정말 단열이 뛰어난 창호만이 1등급을 받을 수 있게 되었고, 소비자들은 더욱 효율적인 창호를 선택할 수 있게 되었습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">창호 등급제와 정부 정책의 변화</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p>창호 소비효율 등급제는 단순한 제품 비교를 위한 것이 아닙니다. <strong>정부의 에너지 절감 정책과도 깊은 관련</strong>이 있습니다.<br>
|
||||
● 2020년 부터 <strong>그린리모델링 사업</strong>을 통해 단열 성능이 높은 창호로 교체하면 <strong>정부 보조금</strong>을 받을 수 있도록 지원하고 있습니다.<br>
|
||||
● 2023년 이후, 건물에너지 절감을 위해 신축 건물뿐만 아니라 기존 건물에도 <strong>고효율 창호 설치가 의무화</strong>되는 방향으로 정책이 강화되고 있습니다.<br>
|
||||
이런 흐름 속에서 창호 소비효율 등급제는 점점 더 중요해지고 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">소비자에게 주는 의미: 더 나은 선택을 위한 기준</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p>예전에는 창호를 고를 때 가격과 디자인만을 고려했지만, 이제는 <strong>창호 성능을 꼼꼼히 따져봐야 하는 시대</strong>가 되었습니다.<br>
|
||||
✔ 1등급 창호는 <strong>단열이 뛰어나 난방비 절약</strong> 효과가 크고,<br>
|
||||
✔ 등급이 낮을수록 실내 온도 유지가 어렵고 에너지 낭비가 심해질 수 있습니다.<br>
|
||||
창호 소비효율 등급제는 <strong>우리 가족이 보다 쾌적한 환경에서 생활할 수 있도록 돕는 중요한 기준</strong>입니다. 이제 창호를 교체할 때는 반드시 <strong>소비효율 등급을 확인</strong>하고, 현명한 선택을 하세요!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg2">
|
||||
<div class="inner">
|
||||
<h2>Hi 고객스토리</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub02.php">창호견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_1.php">시공견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_2.php">창호소비효율등급제</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub02_3.php">창호리모델링시대</a></li>
|
||||
<li class="swiper-slide "><a href="/sub02_4.php">고객이 알아야 할 창호시공 10선</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>창호리모델링시대</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<h3 class="doc-tit"><font color="#003300">집의 가치를 높이는 창호 리모델링, 왜 필요할까요?</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-5"><center><img class="img-responsive" src="/theme/rd.lwd/img/sub/sub/dn04.jpg" alt=""/></center></div>
|
||||
<div class="col-lg-7">
|
||||
<p>최근 몇 년 사이, <strong>창호 리모델링 시장이 빠르게 성장</strong>하고 있습니다.<br>
|
||||
특히 코로나19 이후, 집에 머무는 시간이 늘어나면서 많은 가정에서 창호 교체를 고민하게 되었습니다.<br>
|
||||
이전에는 바쁜 일상 때문에 미뤄왔던 창호 교체가, 이제는 실내 환경을 개선하는 필수적인 선택이 되고 있습니다.<br>
|
||||
그렇다면, 창호 리모델링이 왜 중요한 걸까요?</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">단열과 에너지 절약, 생활비 절감의 시작</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-7">
|
||||
<p>창호는 집 안의 온도를 유지하는 중요한 요소입니다. 오래된 창문은 틈새 바람이 많아 <strong>겨울엔 난방비가 오르고, 여름엔 에어컨 효율이 떨어지는</strong> 문제가 발생합니다.<br>하지만 최신 창호는 <strong>단열 성능이 뛰어나 에너지 절약 효과</strong>가 크며, 장기적으로 보면 난방비와 냉방비를 절약할 수 있습니다.<br>
|
||||
특히 정부에서는 <strong>창호 소비효율 등급제</strong>를 도입해, 에너지 성능이 뛰어난 창호를 선택할 수 있도록 하고 있습니다. 또한 <strong>그린리모델링 지원 사업</strong>을 통해 에너지 절약형 창호로 교체하는 가정에 <strong>정부 지원금 혜택</strong>도 제공하고 있습니다.<br>이제 창호 교체는 단순한 인테리어가 아니라 <strong>경제적이고 환경을 생각하는 필수 투자</strong>가 되고 있는 것입니다.</p>
|
||||
</div>
|
||||
<div class="col-lg-5"><center><img class="img-responsive" src="/theme/rd.lwd/img/sub/sub/dn05.jpg" alt=""/></center></div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #eee; margin-bottom: 30px; margin-top: 10px;"></div>
|
||||
|
||||
<h3 class="doc-tit"><font color="#003300">신축보다 ‘이동 시대’, 이사 가도 바뀌는 주거 환경</font></h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-4"><center><img class="img-responsive" src="/theme/rd.lwd/img/sub/sub/dn06.jpg" alt=""/></center></div>
|
||||
<div class="col-lg-8">
|
||||
<p>과거에는 새 아파트를 짓고 입주하는 것이 트렌드였지만, <strong>인구 감소로 인해 신축 주택 공급이 줄어</strong>들고 있습니다.<br>
|
||||
이제는 집에서 집으로 이동하며 주거 환경을 개선하는 시대가 왔습니다. 따라서 기존 주택을 보다 쾌적하게 바꾸기 위해 창호 <strong>리모델링을 통해 집의 가치를 높이는 것</strong>이 더욱 중요해졌습니다.<br>특히 <strong>방음과 결로 문제</strong>가 있는 오래된 창호는 쾌적한 생활을 방해합니다. 신혼부부, 어린아이를 키우는 가정, 재택근무를 하는 가정에서는 조용하고 쾌적한 환경이 필수적입니다.<br>창호 리모델링을 하면 <strong>소음 차단 효과</strong>가 뛰어나고, 실내 공기 질을 개선하여 가족의 건강까지 지킬 수 있습니다.<br><strong>창호 리모델링, 더 늦추지 마세요!</strong><br><br>
|
||||
창호는 단순한 ‘창문’이 아닙니다.<br><strong>집 안 공기의 질, 온도 유지, 소음 차단, 에너지 절감</strong>까지 모든 요소에 영향을 미치는 중요한 부분입니다.<br>
|
||||
이제는 단순한 미관 개선이 아니라 <strong>실용적인 이유로 창호 교체가 필수가 된 시대</strong>입니다.<br>
|
||||
정부의 지원이 이루어지고 있는 지금, 창호 리모델링을 고려해보는 것은 어떨까요?<br>
|
||||
우리 가족이 더 건강하고 쾌적한 공간에서 생활할 수 있도록, 현명한 선택을 해보세요!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg2">
|
||||
<div class="inner">
|
||||
<h2>Hi 고객스토리</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub02.php">창호견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_1.php">시공견적</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_2.php">창호소비효율등급제</a></li>
|
||||
<li class="swiper-slide"><a href="/sub02_3.php">창호리모델링시대</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub02_4.php">고객이 알아야 할 창호시공 10선</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>고객이 알아야 할 창호시공 10선</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<h3 class="doc-tit"><font color="#003300">시공을 계획하고 계신가요? 아래는 창호 시공 시 꼭 알아두셔야 할 10가지 사항입니다.</font></h3>
|
||||
<div class="row">
|
||||
<!-- <div class="col-lg-3"><center><img class="img-responsive" src="/images/sub/dn04.jpg" alt=""/></center></div> -->
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#000000">1. 수직·수평 정확도 확인</font></strong><br>
|
||||
창호 시공 시 벽과 바닥의 수직•수평이 정확해야 합니다.<br>
|
||||
작은 오차라도 누적되면 창문이 제대로 닫히지 않거나 틈이 생길 수 있습니다. 시공 전과 후에 수직·수평 정밀도를 반드시 확인하세요.<br><br>
|
||||
|
||||
<strong><font color="#000000">2. 단열의 중요성</font></strong><br>
|
||||
창호는 실내 온도 유지와 에너지 절약에 중요한 역할을 합니다.<br>
|
||||
이중·삼중 유리, 로이(Low-E) 코팅, 우레탄 폼 충진 등 단열 성능이 높은 제품과 시공 방식을 선택해야 냉·난방비 절감 효과를 볼 수 있습니다.<br><br>
|
||||
|
||||
<strong><font color="#000000">3. 실리콘 마감으로 누수 방지</font></strong><br>
|
||||
창문과 벽 사이의 실리콘 마감이 제대로 되어 있지 않으면 누수나 외풍이 발생할 수 있습니다.<br>
|
||||
실리콘이 균일하게 발려 있는지, 틈이 없는지 꼼꼼히 확인하세요.<br><br>
|
||||
|
||||
<strong><font color="#000000">4. 단열 유리 선택</font></strong><br>
|
||||
창문에 단열 유리를 사용하면 외부 온도 변화로부터 실내를 보호할 수 있습니다.<br>
|
||||
특히 겨울철 결로 방지와 냉•난방비 절감 효과가 뛰어나므로, 창문 선택 시 단열 유리 여부를 체크하세요.<br><br>
|
||||
|
||||
<strong><font color="#000000">5. 슬라이딩 도어 및 창문 개폐 성능 확인</font></strong><br>
|
||||
슬라이딩 도어나 여닫이 창이 부드럽게 열리고 닫히는지 확인해야 합니다.<br>
|
||||
창틀과 레일이 정밀하게 맞아야 원활한 작동이 가능하며, 불량한 제품은 사용 시 불편함을 초래할 수 있습니다.<br><br>
|
||||
|
||||
<strong><font color="#000000">6. 잠금장치 및 하드웨어 품질 점검</font></strong><br>
|
||||
창문의 잠금장치, 핸들, 경첩 등 하드웨어 품질이 낮으면 안전 문제나 사용 불편이 발생할 수 있습니다.<br>
|
||||
특히 창문이 자주 여닫히는 공간에서는 내구성이 높은 하드웨어를 사용하는 것이 중요합니다.<br><br>
|
||||
|
||||
<strong><font color="#000000">7. 기밀성과 방음 성능 체크</font></strong><br>
|
||||
창문이 제대로 밀폐되지 않으면 외풍이 들어오고 소음이 차단되지 않습니다.<br>
|
||||
기밀 성능이 높은 제품을 선택하고, 창틀과 유리 접합 부위의 마감 상태를 점검하세요.<br><br>
|
||||
|
||||
<strong><font color="#000000">8. 폐기물 처리 방법 확인</font></strong><br>
|
||||
기존 창호 철거 시 발생하는 폐기물 처리 비용과 방법을 미리 확인해야 합니다.<br>
|
||||
일부 업체는 별도의 폐기물 처리 비용을 청구할 수 있으므로 계약 전에 포함 여부를 체크하세요.<br><br>
|
||||
|
||||
<strong><font color="#000000">9. A/S 기간 및 보증 조건 체크</font></strong><br>
|
||||
창호 시공 후 문제가 발생할 수 있으므로, 제품과 시공의 A/S 기간과 보증 조건을 꼼꼼히 확인해야 합니다.<br>
|
||||
창틀, 유리, 하드웨어 등에 대한 보증 기간이 각각 다를 수 있으니 사전에 계약서를 확인하세요.<br><br>
|
||||
|
||||
<strong><font color="#000000">10. 창문 몰딩 설치 여부</font></strong><br>
|
||||
창문과 벽체 사이의 마감을 깔끔하게 처리하려면 몰딩을 설치할 수 있습니다.<br>
|
||||
몰딩은 단열 및 방음 성능 향상에도 도움이 되며, 인테리어적으로도 완성도를 높일 수 있습니다. 하지만 추가 비용이 발생할 수 있으므로, 설치 여부를 미리 결정하는 것이 좋습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg3">
|
||||
<div class="inner">
|
||||
<h2>창호 STORY</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide active "><a href="/sub03.php">창호제작 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_2.php">시공 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_3.php">유리 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_4.php">창호소재·종류 STORY</a></li>
|
||||
<li class="swiper-slide"><a href="/sub03_5.php">창호브랜드</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>시공 STORY</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<!-- <h3 class="doc-tit"><font color="#003300">시공을 계획하고 계신가요? 아래는 창호 시공 시 꼭 알아두셔야 할 10가지 사항입니다.</font></h3> -->
|
||||
<div class="row">
|
||||
<!-- <div class="col-lg-3"><center><img class="img-responsive" src="/images/sub/dn04.jpg" alt=""/></center></div> -->
|
||||
<div class="col-lg-6">
|
||||
<p><strong><font color="#000000">1. 원자재 선택</font></strong><br>
|
||||
창호의 틀이 되는 알루미늄 또는 PVC 프로파일을 선택해요.<br>
|
||||
(PVC는 단열이 좋고, 알루미늄은 내구성이 뛰어나요!)
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">2. 창호 절단</font></strong><br>
|
||||
우리 집 창호 크기에 맞춰 프로파일을 정밀하게 절단해요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">3. 보강재 삽입</font></strong><br>
|
||||
PVC 창호 안에 강철 보강재를 넣어 튼튼하게 만들어요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">4. 피스 체결</font></strong><br>
|
||||
각 부품을 **나사(피스)**로 조립해 창틀을 완성해요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">5. 모헤어 체결</font></strong><br>
|
||||
창문 틈새에서 **바람이 새는 걸 막아주는 털(모헤어)**을 부착해요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">6. 하드웨어 부착</font></strong><br>
|
||||
손잡이, 경첩, 잠금장치 같은 **부자재(하드웨어)**를 설치해요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">7. 창호 용접</font></strong><br>
|
||||
창틀 모서리를 고온으로 용접하여 튼튼하게 고정해요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">8. 방충망 제작</font></strong><br>
|
||||
여름철 필수템! 벌레가 들어오지 않도록 방충망을 만들어 부착해요.
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">9. 창호 유리 삽입</font></strong><br>
|
||||
단열, 방음 효과를 높이는 유리를 창틀에 끼워 넣어요. (복층유리 사용 가능!)<br><br>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong><font color="#000000">10. 완성창 완성!</font></strong><br>
|
||||
마지막 점검 후, 우리 집에 설치될 튼튼하고 아름다운 창호 완성!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg3">
|
||||
<div class="inner">
|
||||
<h2>창호 STORY</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub03.php">창호제작 STORY</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub03_2.php">시공 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_3.php">유리 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_4.php">창호소재·종류 STORY</a></li>
|
||||
<li class="swiper-slide"><a href="/sub03_5.php">창호브랜드</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>시공 STORY</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<h3 class="doc-tit"><font color="#3366cc">창문을 교체하려는데, 어떻게 진행되는지 궁금하시죠? 걱정 마세요! 하나하나 차근차근 설명해 드릴게요.</font></h3>
|
||||
<div class="row">
|
||||
<!-- <div class="col-lg-3"><center><img class="img-responsive" src="/images/sub/dn04.jpg" alt=""/></center></div> -->
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">1단계: 보호 작업 (보양) – 우리 집을 깨끗하게 지키는 과정!</font></strong><br>
|
||||
<i class="xi-help"></i><strong>주부님</strong> : 시공할 때 집이 많이 더러워지거나 가구가 망가질까 걱정돼요. 어떻게 하나요?<br>
|
||||
<i class="xi-profile"></i><strong>시공자</strong> : 네, 그런 걱정 많으시죠! 창문 공사를 할 때 먼지가 날리고 가구가 긁힐 수도 있어서, 미리 보호 작업을 해요.</p>
|
||||
<p><strong><font color="#000000">우리가 하는 일</font></strong><br>
|
||||
<i class="xi-toggle-on"></i> 깨지기 쉬운 물건(화분, 액자, 도자기 등)은 안전한 곳으로 옮겨요.<br>
|
||||
<i class="xi-toggle-on"></i> 소파, 식탁, 책상 같은 큰 가구는 작업 공간에서 잠시 이동해 둬요.<br>
|
||||
<i class="xi-toggle-on"></i> 먼지가 날릴 수 있으니 바닥에 보호 매트를 깔아요.<br>
|
||||
<i class="xi-toggle-on"></i> 공사가 끝나면 가구를 원래 자리로 돌려놓고 깨끗하게 정리해 드려요.</p>
|
||||
|
||||
<p><strong><font color="#000000">주부님 TIP!</font></strong><br>
|
||||
<i class="xi-key"></i> 보양 작업을 미리 해 두면 청소하는 시간이 줄어들어요!</p>
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">2단계: 기존 창문 철거 – 낡은 창문을 조심스럽게 제거하는 과정!</font></strong><br>
|
||||
<i class="xi-help"></i><strong>주부님</strong> : 기존 창문을 떼어낼 때 벽이 망가지진 않을까요?<br>
|
||||
<i class="xi-profile"></i><strong>시공자</strong> : 좋은 질문이에요! 창문을 급하게 철거하면 벽지나 타일이 손상될 수 있어서, 최대한 조심스럽게 작업해요.</p>
|
||||
<p><strong><font color="#000000">우리가 신경 쓰는 부분</font></strong><br>
|
||||
<i class="xi-toggle-on"></i> 창문을 떼어낼 때 벽지, 타일, 바닥이 다치지 않도록 신중하게 철거해요.<br>
|
||||
<i class="xi-toggle-on"></i> 철거 후 창문 주변을 살펴보고, 손상된 부분이 없는지 확인해요.</p>
|
||||
|
||||
<p><strong><font color="#000000">주부님 TIP!</font></strong><br>
|
||||
<i class="xi-key"></i> 기존 창문을 철거하면서 벽이나 타일이 손상되었는지 한 번 더 체크해 주세요!</p>
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">3단계: 새 창문 옮기기(양중) – 새로운 창문을 안전하게 들여오는 과정!</font></strong><br>
|
||||
<i class="xi-help"></i><strong>주부님</strong> : 새 창문이 도착하면 어떻게 운반하나요?<br>
|
||||
<i class="xi-profile"></i><strong>시공자</strong> : 창문은 크고 무겁기 때문에 안전하게 옮기는 게 제일 중요해요.</p>
|
||||
<p><strong><font color="#000000">우리가 신경 쓰는 부분</font></strong><br>
|
||||
<i class="xi-toggle-on"></i> 창문을 조심스럽게 옮겨서 벽이나 바닥이 손상되지 않도록 해요.<br>
|
||||
<i class="xi-toggle-on"></i> 아이들이 다칠 위험이 있으니, 주변에 안전거리를 확보해요.</p>
|
||||
|
||||
<p><strong><font color="#000000">주부님 TIP!</font></strong><br>
|
||||
<i class="xi-key"></i> 창문 운반 중 아이들이 주변에서 뛰어놀지 않도록 주의해 주세요!</p>
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">4단계: 새 창문 설치(시공) – 창문을 튼튼하게 고정하는 과정!</font></strong><br>
|
||||
<i class="xi-help"></i><strong>주부님</strong> : 창문이 바람이 새거나 삐뚤어지진 않을까요?<br>
|
||||
<i class="xi-profile"></i><strong>시공자</strong> : 그런 걱정하지 않으셔도 돼요! 창문이 완벽하게 고정되도록 꼼꼼하게 작업해요.</p>
|
||||
<p><strong><font color="#000000">우리가 하는 일</font></strong><br>
|
||||
<i class="xi-toggle-on"></i> 창문이 기울어지지 않도록 수평을 맞춰서 설치해요.<br>
|
||||
<i class="xi-toggle-on"></i> 창틀을 튼튼하게 고정해서 흔들리지 않도록 해요.</p>
|
||||
<i class="xi-toggle-on"></i> 창문과 벽 사이의 틈을 막기 위해 우레탄폼과 실리콘을 꼼꼼하게 발라요.</p>
|
||||
|
||||
<p><strong><font color="#000000">주부님 TIP!</font></strong><br>
|
||||
<i class="xi-key"></i> 창문 설치 후 열고 닫아보면서 이상이 없는지 직접 확인해 보세요!</p>
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">5단계: 마무리 정리 – 깨끗하게 마무리하고 사용법을 알려드리는 과정!</font></strong><br>
|
||||
<i class="xi-help"></i><strong>주부님</strong> : 시공이 끝난 후, 어떤 걸 확인해야 하나요?<br>
|
||||
<i class="xi-profile"></i><strong>시공자</strong> : 공사가 끝나면 마무리 작업을 하고, 주부님께 사용 방법과 주의 사항을 설명해 드려요.</p>
|
||||
<p><strong><font color="#000000">우리가 하는 일</font></strong><br>
|
||||
<i class="xi-toggle-on"></i> 창문 손잡이를 설치하고, 정상적으로 열리고 닫히는지 확인해요.<br>
|
||||
<i class="xi-toggle-on"></i> 보호 매트와 보양재를 치우고, 주변을 깨끗하게 정리해요.</p>
|
||||
<i class="xi-toggle-on"></i> 창문 사용 방법과 A/S 관련 사항을 안내해 드려요.</p>
|
||||
|
||||
<p><strong><font color="#000000">주부님 TIP!</font></strong><br>
|
||||
<i class="xi-key"></i> 창문이 잘 닫히는지, 잠금장치가 제대로 작동하는지 직접 테스트해 보세요!</p>
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">한눈에 보는 창문 교체 과정!</font></strong><br>
|
||||
1. 보호 작업 – 가구와 물건을 정리해서 깨끗한 작업 환경을 만든다!<br>
|
||||
2. 철거 작업 – 오래된 창문을 조심스럽게 제거한다!<br>
|
||||
3. 새 창문 옮기기 – 안전하게 새 창문을 들여온다!<br>
|
||||
4. 새 창문 설치 – 창문이 흔들리지 않도록 튼튼하게 고정한다!<br>
|
||||
5. 마무리 정리 – 깨끗하게 정리하고 창문 사용법을 배운다!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg3">
|
||||
<div class="inner">
|
||||
<h2>창호 STORY</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub03.php">창호제작 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_2.php">시공 STORY</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub03_3.php">유리 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_4.php">창호소재·종류 STORY</a></li>
|
||||
<li class="swiper-slide"><a href="/sub03_5.php">창호브랜드</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>유리 STORY</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<!-- <h3 class="doc-tit"><font color="#3366cc">창문을 교체하려는데, 어떻게 진행되는지 궁금하시죠? 걱정 마세요! 하나하나 차근차근 설명해 드릴게요.</font></h3> -->
|
||||
<p>모든 유리는 기본적으로 판유리(Flat Glass)에서 출발합니다. 판유리는 플로트 공법을 통해 대량 생산되며, 이후 다양한 가공 과정을 거쳐 접합유리, 복층유리, 인테리어유리, 코팅유리 등의 형태로 발전됩니다.<br>창문에 사용되는 유리는 복층유리와 코팅유리입니다. 과거에는 코팅유리에 대한 수요가 적었지만 ‘창호소비효율등급제’의 도입으로 코팅유리 사용이 급격하게 늘어나고 있습니다.</p>
|
||||
<div class="row">
|
||||
<!-- <div class="col-lg-3"><center><img class="img-responsive" src="/images/sub/dn04.jpg" alt=""/></center></div> -->
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">- 판유리 제작 과정(Flat Glass Manufacturing Process)</font></strong><br>
|
||||
<strong>① 원료 혼합 (Batching)</strong><br>
|
||||
● 주원료: 실리카 모래(SiO₂), 소다회(Na₂CO₃), 석회석(CaCO₃)<br>
|
||||
● 첨가제: 철분 제거제(투명도 증가), 산화알루미늄(내구성 증가) 등<br>
|
||||
● 철저한 비율로 혼합 후 용융로로 이동<br>
|
||||
<strong>② 용융 (Melting)</strong><br>
|
||||
● 1,500°C 이상의 고온에서 **용융로(Furnace)**에서 가열하여 유리 원료를 녹임<br>
|
||||
● 불순물을 제거하고 균질한 유리 용융물 형성<br>
|
||||
<strong>③ 플로트 공법 (Float Process)</strong><br>
|
||||
● 녹은 유리를 주석(Tin) 용탕 위에 부어 자연스럽게 평평한 형태로 만듦<br>
|
||||
● 주석 위에서 유리가 부유하면서 매끄럽고 균일한 표면 형성<br>
|
||||
<strong>④ 냉각 및 어닐링 (Cooling & Annealing)</strong><br>
|
||||
● **어닐링로(Annealing Lehr)**에서 서서히 냉각하여 내부 응력 제거<br>
|
||||
● 강도와 내구성 확보<br>
|
||||
<strong>⑤ 절단 및 가공 (Cutting & Processing)</strong><br>
|
||||
● 원하는 크기와 두께로 절단 후, 필요에 따라 연마, 강화, 코팅 등 추가 가공 진행</p>
|
||||
|
||||
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">- 판유리에서 다양한 유리로 가공(Types of Processed Glass)</font></strong><br>
|
||||
<strong><font color="#660000"><i class="xi-check-square"></i> 접합유리 (Laminated Glass)</font></strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>특징 : 두 장 이상의 유리 사이에 PVB(Polyvinyl Butyral) 필름을 넣고 압착하여 만든 유리</strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>제작 원리</strong><br>
|
||||
1. 두 장 이상의 판유리 사이에 <strong>PVB 필름</strong> 삽입<br>
|
||||
2. 고온과 압력을 가해 유리와 필름을 밀착<br>
|
||||
3. 충격을 받아도 파편이 필름에 붙어 있어 <strong>안전성 강화</strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>사용처: 자동차 유리, 방탄 유리, 고층 건물 외벽</strong></p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p><strong><font color="#660000"><i class="xi-check-square"></i> 복층유리(Insulated Glass, IGU)</font></strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>특징 : 두 장 이상의 유리 사이에 **공기층(또는 가스층)**을 두어 단열 및 방음 효과를 높인 유리</strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>제작 원리</strong><br>
|
||||
1. 두 장 이상의 유리를 절단 및 세척<br>
|
||||
2. 유리 사이에 간봉(Spacer) + 건조제(Desiccant) 삽입<br>
|
||||
3. 내부 공간에 아르곤(Argon) 가스 또는 공기 주입<br>
|
||||
4. 실란트(Sealant)로 완전 밀봉<br>
|
||||
<i class="xi-check-square-o"></i> <strong>사용처: 건축 외장재, 에너지 절약 창호, 친환경 건물</strong></p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p><strong><font color="#660000"><i class="xi-check-square"></i> 인테리어유리(Interior Glass)</font></strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>특징 : 다양한 패턴, 색상, 질감을 적용해 미적 감각을 높인 유리</strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>종류 및 제작 원리</strong><br>
|
||||
● <strong>강화유리(Tempered Glass)</strong>: 급속 냉각하여 충격 저항을 높임 (샤워 부스, 테이블)<br>
|
||||
● <strong>패턴유리(Patterned Glass)</strong>: 롤러 프레스 방식으로 표면에 무늬를 새김 (파티션, 문)<br>
|
||||
● <strong>컬러유리(Tinted Glass)</strong>: 산화금속을 첨가하여 색상을 부여 (인테리어 장식)<br>
|
||||
<i class="xi-check-square-o"></i> <strong>사용처: 실내 디자인, 가구, 파티션, 샤워부스</strong></p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p><strong><font color="#660000"><i class="xi-check-square"></i> 코팅유리(Coated Glass)</font></strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>특징 : 유리 표면에 특수 코팅을 하여 기능성을 강화한 유리</strong><br>
|
||||
<i class="xi-check-square-o"></i> <strong>종류 및 제작 원리</strong><br>
|
||||
● <strong>로이유리(Low-E Glass)</strong>: 적외선 반사 코팅 → 단열 성능 증가<br>
|
||||
● <strong>반사유리(Reflective Glass)</strong>: 금속 산화물 코팅 → 태양열 차단<br>
|
||||
● <strong>자가청정유리(Self-Cleaning Glass)</strong>: 나노 코팅 → 빗물로 먼지를 자동 세척<br>
|
||||
<i class="xi-check-square-o"></i> <strong>사용처: 에너지 절약 창호, 고급 건물 외벽, 친환경 건축</strong></p>
|
||||
|
||||
<div style="height: 1px; background-color: #eee;"></div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">- 유리 가공별 차이점</font></strong></p>
|
||||
<!-- 표 -->
|
||||
<div class="doc-cnt">
|
||||
<div class="mana-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>유리 종류</th>
|
||||
<th>특징</th>
|
||||
<th>제작 원리</th>
|
||||
<th>주요 용도</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><center><strong>접합유리</strong></center></td>
|
||||
<td><center>안전성 강화</center></td>
|
||||
<td>PVB 필름 접합</td>
|
||||
<td>자동차, 방탄 유리</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>복층유리</strong></center></td>
|
||||
<td><center>단열, 방음</center></td>
|
||||
<td>유리 사이 공기층 형성</td>
|
||||
<td>창호, 건축 외장재</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>인테리어유리</strong></center></td>
|
||||
<td><center>미적 감각</center></td>
|
||||
<td>강화, 패턴, 컬러 적용</td>
|
||||
<td>실내 디자인, 가구</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>코팅유리</strong></center></td>
|
||||
<td><center>기능성 강화</center></td>
|
||||
<td>로이, 반사, 자가청정 코팅</td>
|
||||
<td>에너지 절감, 친환경 건축</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- //표 -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg3">
|
||||
<div class="inner">
|
||||
<h2>창호 STORY</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub03.php">창호제작 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_2.php">시공 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_3.php">유리 STORY</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub03_4.php">창호소재·종류 STORY</a></li>
|
||||
<li class="swiper-slide"><a href="/sub03_5.php">창호브랜드</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>창호소재·종류 STORY</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<!-- <h3 class="doc-tit"><font color="#3366cc">창문을 교체하려는데, 어떻게 진행되는지 궁금하시죠? 걱정 마세요! 하나하나 차근차근 설명해 드릴게요.</font></h3> -->
|
||||
<p><strong><font color="#000000">창의 형태별 분류와 특성, 설치 장소</font></strong><br>
|
||||
창호는 건물의 디자인과 기능성을 결정하는 중요한 요소로, 설치 목적과 구조에 따라 다양한 형태로 나뉩니다. 여기에서는 대표적인 창의 형태(단창, 이중창, 발코니창 등)를 설명하고, 각각의 <strong>특성</strong>과 <strong>설치 장소</strong>를 정리해보겠습니다.</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">단창(Single Window, 單窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 유리 한 장(1겹)으로 된 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 유리가 한 장만 사용되기 때문에 <strong>단열 성능이 낮음</strong><br>
|
||||
● <strong>가격이 저렴하고 가벼움</strong><br>
|
||||
● 방음, 기밀성, 단열 성능이 상대적으로 부족<br>
|
||||
● 과거에는 많이 사용되었으나, 현재는 <strong>주택에서는 거의 사용되지 않음</strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 창고, 실외 기계실, 임시 건물 등<br>
|
||||
● 단열이 크게 중요하지 않은 공간</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">이중창(Double Window, 二重窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 두 개의 창이 앞뒤로 이중 구조를 이루는 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 창이 두 겹으로 되어 있어 <strong>단열·방음 성능이 우수</strong><br>
|
||||
● 외창(AL창)과 내창(PVC창) 조합으로 제작 가능<br>
|
||||
● <strong>겨울철 결로 방지 효과가 뛰어남</strong><br>
|
||||
● 개폐 방식에 따라 <strong>미서기창, 여닫이창, 고정창</strong> 등 다양한 형태로 제작<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 단열이 중요한 <strong>거실, 침실, 발코니 등 주거 공간</strong><br>
|
||||
● 고층 아파트, 빌라 등 <strong>외부 소음이 심한 곳</strong><br>
|
||||
● 난방비 절감을 원하는 공간</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">발코니창(Balcony Window, 陽臺窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 발코니와 실내 공간을 구분하는 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 일반적으로 <strong>이중창 구조</strong>를 사용하여 단열•방음 성능 강화<br>
|
||||
● 단열 및 방음 효과가 좋아야 하며, 내•외부 기밀성이 중요<br>
|
||||
● 개폐 방식은 <strong>미서기형(슬라이딩형)이 가장 일반적</strong><br>
|
||||
● 일부 아파트에서는 발코니 확장 공사로 인해 제거되기도 함<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 아파트, 빌라 발코니 공간<br>
|
||||
● 외부와 연결된 테라스, 베란다</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">고정창(Fixed Window, 固定窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 열리지 않는 창 (개폐 불가능)</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 개방 기능이 없는 <strong>유리만 있는 구조</strong><br>
|
||||
● 주로 <strong>채광을 위한 용도</strong>로 사용<br>
|
||||
● 단열 및 방음 성능이 높음 (틈이 없음)<br>
|
||||
● 디자인 요소로 활용되며, 다른 창과 함께 조합하는 경우 많음<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 상업 건물의 외관 창 (고층 빌딩 등)<br>
|
||||
● 조망이 중요한 거실, 호텔, 카페<br>
|
||||
● 계단실, 복도 등 채광이 필요한 공간</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">미서기창(Sliding Window, 片引窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 좌우로 미는 방식(슬라이딩)으로 여닫는 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 가장 보편적으로 사용되는 개폐 방식<br>
|
||||
● 공간 활용도가 높아 좁은 공간에서도 설치 가능<br>
|
||||
● 단열, 기밀성은 여닫이창보다 낮음 (틈이 생길 가능성이 있음)<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 거실, 침실, 발코니, 주방<br>
|
||||
● 좁은 공간이 많은 소형 아파트, 빌라</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">여닫이창(Casement Window, 開閉窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 안쪽 또는 바깥쪽으로 열리는 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● <strong>기밀성과 단열 성능이 뛰어남</strong>(틈이 없음)<br>
|
||||
● 완전히 개방할 수 있어 <strong>환기 효과가 좋음</strong><br>
|
||||
● 바람이 강한 날에는 흔들리거나 파손될 위험이 있음<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 단독주택, 고급 주거공간<br>
|
||||
● 전원주택, 별장, 호텔</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">폴딩도어(Folding Door, 折りたたみ窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 접이식으로 여러 장의 창을 접었다 펴는 구조</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 넓은 개방감을 제공하며 <strong>실내외 연결성이 뛰어남</strong><br>
|
||||
● 일반 창보다 <strong>비용이 높고 설치 난이도가 있음</strong><br>
|
||||
● 공간 활용성이 좋아 카페나 고급 주택에서 많이 사용<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 테라스, 실내외 연결 공간 (거실 ↔ 마당)<br>
|
||||
● 카페, 레스토랑, 상업용 공간</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">망입유리창(Wire Glass Window, 網入玻璃窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 유리 내부에 철망이 삽입된 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 유리가 깨져도 <strong>파편이 날리지 않도록 설계</strong><br>
|
||||
● 화재 발생 시 <strong>화염 확산을 방지하는 역할</strong><br>
|
||||
● 방범·안전성을 고려한 창<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 공장, 창고, 학교, 화재 위험이 높은 건물<br>
|
||||
● 방범이 필요한 상업시설</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3 class="doc-tit"><font color="#003300">루버창(Louver Window, 羽板窓)</font></h3>
|
||||
<p><strong><font color="#000000"><i class="xi-check-square"></i> 여러 개의 가로 날개(루버)를 조절하여 개폐하는 창</font></strong><br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 특성</font></strong><br>
|
||||
● 개방 각도를 조절하여 <strong>바람 조절 및 환기가 용이</strong><br>
|
||||
● 외부에서 내부가 잘 보이지 않아 <strong>프라이버시 보호 효과</strong><br>
|
||||
● 방수 및 기밀성이 낮아 비바람이 많은 지역에서는 사용 제한<br>
|
||||
<strong><font color="#000000"><i class="xi-check-square"></i> 설치 장소</font></strong><br>
|
||||
● 화장실, 욕실, 보일러실, 기계실<br>
|
||||
● 환기가 필요한 공간</p>
|
||||
|
||||
<!-- <div style="height: 1px; background-color: #eee;"></div> -->
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<p><strong><font color="#cc0000">- 창 형태별 주요 비교</font></strong></p>
|
||||
<!-- 표 -->
|
||||
<div class="doc-cnt">
|
||||
<div class="mana-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>창 종류</th>
|
||||
<th>개폐 방식</th>
|
||||
<th>단열성</th>
|
||||
<th>방음성</th>
|
||||
<th>특징</th>
|
||||
<th>주로 쓰이는 장소</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><center><strong>단창</strong></center></td>
|
||||
<td>단일 유리</td>
|
||||
<td><center>낮음</center></td>
|
||||
<td><center>낮음</center></td>
|
||||
<td>저렴하지만 단열·방음 약함</td>
|
||||
<td>창고, 실외 공간</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>이중창</strong></center></td>
|
||||
<td>슬라이딩 or 여닫이</td>
|
||||
<td><center>높음</center></td>
|
||||
<td><center>높음</center></td>
|
||||
<td>외창+내창 구조, 단열성 우수</td>
|
||||
<td>주거공간, 거실, 침실</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>발코니창</strong></center></td>
|
||||
<td>슬라이딩</td>
|
||||
<td><center>높음</center></td>
|
||||
<td><center>높음</center></td>
|
||||
<td>발코니 확장 시 중요</td>
|
||||
<td>아파트, 빌라 발코니</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>고정창</strong></center></td>
|
||||
<td>없음</td>
|
||||
<td><center>높음</center></td>
|
||||
<td><center>높음</center></td>
|
||||
<td>개폐 불가능, 조망·채광용</td>
|
||||
<td>빌딩, 카페, 거실</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>미서기창</strong></center></td>
|
||||
<td>좌우 슬라이딩</td>
|
||||
<td><center>보통</center></td>
|
||||
<td><center>보통</center></td>
|
||||
<td>공간 활용도 높음</td>
|
||||
<td>거실, 주방, 발코니</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>여닫이창</strong></center></td>
|
||||
<td>안팎 개폐</td>
|
||||
<td><center>높음</center></td>
|
||||
<td><center>높음</center></td>
|
||||
<td>기밀성 우수, 환기 효과 큼</td>
|
||||
<td>전원주택, 고급 주택</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>폴딩도어</strong></center></td>
|
||||
<td>접이식</td>
|
||||
<td><center>보통</center></td>
|
||||
<td><center>보통</center></td>
|
||||
<td>넓은 개방감</td>
|
||||
<td>테라스, 카페</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>망입유리창</strong></center></td>
|
||||
<td>없음</td>
|
||||
<td><center>보통</center></td>
|
||||
<td><center>보통</center></td>
|
||||
<td>화재·방범 보호</td>
|
||||
<td>공장, 창고</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><center><strong>루버창</strong></center></td>
|
||||
<td>날개 조절</td>
|
||||
<td><center>낮음</center></td>
|
||||
<td><center>낮음</center></td>
|
||||
<td>환기 용이, 방수 약함</td>
|
||||
<td>욕실, 기계실</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- //표 -->
|
||||
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<h3 class="doc-tit"><font color="#003300">결론</font></h3>
|
||||
<p>● 단열·방음이 중요하다면? → <strong>이중창, 여닫이창</strong><br>
|
||||
● 개방감이 필요하다면? → <strong>폴딩도어</strong><br>
|
||||
● 환기가 중요하다면? → <strong>루버창</strong><br>
|
||||
● 방범•안전이 필요하다면? → <strong>망입유리창</strong><br>
|
||||
용도와 공간 특성을 고려하여 적절한 창을 선택하는 것이 중요합니다.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
include_once './_common.php';
|
||||
include_once G5_LIB_PATH.'/thumbnail.lib.php';
|
||||
include_once G5_PATH.'/head.php';
|
||||
?>
|
||||
|
||||
<!-- for mobile -->
|
||||
<div id="menu" class="mobile-navigation">
|
||||
<div class="home"><a href="/"><img src="/theme/rd.lwd/img/sub/common/logo.png" alt="하이창호"></a></div>
|
||||
<nav class="nav-menu"></nav>
|
||||
<a href="javascript:void(0);" class="close">닫기</a>
|
||||
</div>
|
||||
<div class="mobile-overlay"></div>
|
||||
<div class="sub-visual bg3">
|
||||
<div class="inner">
|
||||
<h2>창호 STORY</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lnb-wrap">
|
||||
<div class="lnb">
|
||||
<div class="swiper-container">
|
||||
<ul class="swiper-wrapper">
|
||||
<li class="swiper-slide "><a href="/sub03.php">창호제작 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_2.php">시공 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_3.php">유리 STORY</a></li>
|
||||
<li class="swiper-slide "><a href="/sub03_4.php">창호소재·종류 STORY</a></li>
|
||||
<li class="swiper-slide active "><a href="/sub03_5.php">창호브랜드</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="contArea">
|
||||
<div class="sub-title">
|
||||
<h2>창호브랜드</h2>
|
||||
</div>
|
||||
<div class="real-cont">
|
||||
|
||||
<!--// content -->
|
||||
<div class="greetings">
|
||||
|
||||
<style>
|
||||
/*** 이실장님 제공소스 ***/
|
||||
@media screen and (max-width:992px){
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex-direction: column;}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="content">
|
||||
<!-- <h3 class="doc-tit"><font color="#3366cc">창문을 교체하려는데, 어떻게 진행되는지 궁금하시죠? 걱정 마세요! 하나하나 차근차근 설명해 드릴게요.</font></h3> -->
|
||||
<p><!-- <strong><font color="#000000">창의 형태별 분류와 특성, 설치 장소</font></strong><br> -->
|
||||
<center>준비중입니다!</center></p>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content //-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_PATH.'/tail.php');
|
||||
?>
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// 디버깅: config.php 로드됨
|
||||
error_log('survey_form config.php loaded');
|
||||
|
||||
// 설문 목록 가져오기
|
||||
$survey_options = array();
|
||||
$survey_sql = "SELECT sv_id, sv_title, sv_status FROM survey_master ORDER BY sv_created_at DESC";
|
||||
$survey_result = sql_query($survey_sql);
|
||||
while ($survey = sql_fetch_array($survey_result)) {
|
||||
$status_text = '';
|
||||
switch($survey['sv_status']) {
|
||||
case 'active': $status_text = ' (진행중)'; break;
|
||||
case 'draft': $status_text = ' (임시저장)'; break;
|
||||
case 'closed': $status_text = ' (종료)'; break;
|
||||
}
|
||||
$survey_options[$survey['sv_id']] = $survey['sv_title'] . $status_text;
|
||||
}
|
||||
|
||||
// 현재 설정값 가져오기
|
||||
$current_sv_id = '';
|
||||
if (isset($row_mod['md_custom_survey_key']) && $row_mod['md_custom_survey_key']) {
|
||||
$custom_options = json_decode($row_mod['md_custom_survey_key'], true);
|
||||
if (isset($custom_options['sv_id'])) {
|
||||
$current_sv_id = $custom_options['sv_id'];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="module-config-section">
|
||||
<h4><i class="fa fa-clipboard"></i> 설문 폼 모듈 설정</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="survey_select">표시할 설문 선택:</label>
|
||||
<select name="custom_options[sv_id]" id="survey_select" class="form-control">
|
||||
<option value="">-- 설문을 선택하세요 --</option>
|
||||
<?php foreach ($survey_options as $sv_id => $sv_title): ?>
|
||||
<option value="<?php echo $sv_id; ?>" <?php echo ($current_sv_id == $sv_id) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($sv_title); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
설문을 선택하지 않으면 사용자가 직접 설문을 선택할 수 있는 인터페이스가 표시됩니다.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<?php if (empty($survey_options)): ?>
|
||||
<div class="alert alert-info">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
등록된 설문이 없습니다.
|
||||
<a href="<?php echo G5_ADMIN_URL; ?>/survey_manage/survey_form.php" target="_blank">새 설문 만들기</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>모듈 사용법:</label>
|
||||
<ul class="usage-list">
|
||||
<li>위에서 설문을 선택하면 해당 설문이 자동으로 표시됩니다.</li>
|
||||
<li>설문을 선택하지 않으면 사용자가 설문을 선택할 수 있는 목록이 표시됩니다.</li>
|
||||
<li>URL에 <code>?sv_id=설문번호</code>를 추가하면 특정 설문을 강제로 표시할 수 있습니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.module-config-section {
|
||||
padding: 20px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
background: #f9f9f9;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.module-config-section h4 {
|
||||
margin-top: 0;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #AA20FF;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px 15px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: #d1ecf1;
|
||||
border-color: #bee5eb;
|
||||
color: #0c5460;
|
||||
}
|
||||
|
||||
.usage-list {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.usage-list li {
|
||||
margin-bottom: 5px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.usage-list code {
|
||||
background: #f1f1f1;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const surveySelect = document.getElementById('survey_select');
|
||||
if (surveySelect) {
|
||||
surveySelect.addEventListener('change', function() {
|
||||
// 설문 선택 시 미리보기나 추가 정보를 표시할 수 있습니다.
|
||||
console.log('선택된 설문 ID:', this.value);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,636 @@
|
||||
/* 설문 폼 모듈 스타일 */
|
||||
.survey-form-module {
|
||||
--survey-primary: #AA20FF;
|
||||
--survey-primary-light: rgba(170, 32, 255, 0.1);
|
||||
--survey-primary-dark: #8A1ACC;
|
||||
}
|
||||
|
||||
.survey-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.survey-header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
padding: 40px 20px;
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.survey-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 5px;
|
||||
background: linear-gradient(90deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
}
|
||||
|
||||
.survey-title {
|
||||
font-size: 2.5em;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.survey-description {
|
||||
font-size: 1.1em;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.survey-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 30px;
|
||||
margin-top: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.survey-info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #888;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.survey-info-item i {
|
||||
color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||||
margin-bottom: 30px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background: #e0e0e0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
border-radius: 4px;
|
||||
transition: width 0.5s ease;
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.survey-form {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
margin-bottom: 40px;
|
||||
padding-bottom: 30px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
animation: fadeInUp 0.6s ease forwards;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.question-container:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.question-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.question-number {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.question-title {
|
||||
font-size: 1.3em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.question-required {
|
||||
color: #e74c3c;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.question-description {
|
||||
margin-top: 10px;
|
||||
color: #666;
|
||||
font-size: 0.95em;
|
||||
line-height: 1.5;
|
||||
margin-left: 45px;
|
||||
}
|
||||
|
||||
.question-input {
|
||||
margin-left: 45px;
|
||||
}
|
||||
|
||||
/* 텍스트 입력 */
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
font-size: 1em;
|
||||
transition: all 0.3s ease;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--survey-primary);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 3px var(--survey-primary-light);
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* 라디오 버튼 */
|
||||
.radio-group,
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.radio-item,
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
background: #fafafa;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.radio-item:hover,
|
||||
.checkbox-item:hover {
|
||||
background: var(--survey-primary-light);
|
||||
border-color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.radio-item.selected,
|
||||
.checkbox-item.selected {
|
||||
background: var(--survey-primary-light);
|
||||
border-color: var(--survey-primary);
|
||||
color: var(--survey-primary-dark);
|
||||
}
|
||||
|
||||
.radio-item input,
|
||||
.checkbox-item input {
|
||||
margin-right: 15px;
|
||||
transform: scale(1.2);
|
||||
accent-color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.radio-item label,
|
||||
.checkbox-item label {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 셀렉트 박스 */
|
||||
.form-select {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
font-size: 1em;
|
||||
background: #fafafa;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.form-select:focus {
|
||||
outline: none;
|
||||
border-color: var(--survey-primary);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 3px var(--survey-primary-light);
|
||||
}
|
||||
|
||||
/* 평점 */
|
||||
.rating-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin: 20px 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.rating-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 60px;
|
||||
background: #fafafa;
|
||||
border: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.rating-item:hover {
|
||||
background: var(--survey-primary-light);
|
||||
border-color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.rating-item.selected {
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
border-color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.rating-number {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.rating-label {
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 날짜 입력 */
|
||||
.form-date {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
padding: 15px 20px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
font-size: 1em;
|
||||
background: #fafafa;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.form-date:focus {
|
||||
outline: none;
|
||||
border-color: var(--survey-primary);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 3px var(--survey-primary-light);
|
||||
}
|
||||
|
||||
/* 제출 버튼 */
|
||||
.submit-container {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
padding-top: 30px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(135deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 18px 50px;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.submit-btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.submit-btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.submit-btn .loading-spinner {
|
||||
display: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid rgba(255,255,255,0.3);
|
||||
border-top: 2px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.submit-btn.loading .loading-spinner {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 확인 모달 */
|
||||
.confirm-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1050;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.confirm-modal.show {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
animation: slideUp 0.4s ease-out;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 25px;
|
||||
font-size: 2rem;
|
||||
color: #aaa;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
z-index: 1;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 30px 30px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.modal-header h3 {
|
||||
font-size: 1.5em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.modal-body p {
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.modal-warning {
|
||||
color: #e74c3c;
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 20px 30px 30px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
padding: 12px 24px;
|
||||
background: #f8f9fa;
|
||||
color: #666;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background: #e9ecef;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
padding: 12px 24px;
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-confirm:hover {
|
||||
background: var(--survey-primary-dark);
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.survey-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.survey-form {
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.survey-title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.survey-info {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.question-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.question-description {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.rating-container {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.rating-item {
|
||||
min-width: 50px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.modal-header,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.btn-cancel,
|
||||
.btn-confirm {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 애니메이션 */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -40%);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 질문 애니메이션 지연 */
|
||||
.question-container:nth-child(1) { animation-delay: 0.1s; }
|
||||
.question-container:nth-child(2) { animation-delay: 0.2s; }
|
||||
.question-container:nth-child(3) { animation-delay: 0.3s; }
|
||||
.question-container:nth-child(4) { animation-delay: 0.4s; }
|
||||
.question-container:nth-child(5) { animation-delay: 0.5s; }
|
||||
|
||||
/* 스크롤 하이라이트 효과 */
|
||||
.question-container.highlight {
|
||||
transform: scale(1.02);
|
||||
box-shadow: 0 5px 20px rgba(170, 32, 255, 0.1);
|
||||
border-color: var(--survey-primary-light);
|
||||
}
|
||||
|
||||
/* 유효성 검사 오류 스타일 */
|
||||
.form-input.error,
|
||||
.form-select.error {
|
||||
border-color: #e74c3c;
|
||||
background: #fdf2f2;
|
||||
}
|
||||
|
||||
.form-input.error:focus,
|
||||
.form-select.error:focus {
|
||||
box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #e74c3c;
|
||||
font-size: 0.9em;
|
||||
margin-top: 8px;
|
||||
margin-left: 45px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error-message.show {
|
||||
display: block;
|
||||
animation: fadeInUp 0.3s ease;
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
function initSurveyFormModule(moduleId) {
|
||||
const moduleElement = document.getElementById(moduleId);
|
||||
if (!moduleElement || moduleElement.classList.contains('initialized')) return;
|
||||
|
||||
// 설문 데이터 가져오기
|
||||
const surveyData = JSON.parse(moduleElement.dataset.survey || '{}');
|
||||
const { survey, questions, theme_color } = surveyData;
|
||||
|
||||
// DOM 요소들
|
||||
const questionsContainer = moduleElement.querySelector('#questionsContainer');
|
||||
const progressFill = moduleElement.querySelector('#progressFill');
|
||||
const progressText = moduleElement.querySelector('#progressText');
|
||||
const currentQuestionSpan = moduleElement.querySelector('#currentQuestion');
|
||||
const submitBtn = moduleElement.querySelector('#submitBtn');
|
||||
const surveyForm = moduleElement.querySelector('#surveyForm');
|
||||
const confirmModal = moduleElement.querySelector('.confirm-modal');
|
||||
const modalOverlay = confirmModal.querySelector('.modal-overlay');
|
||||
const modalClose = confirmModal.querySelector('.modal-close');
|
||||
const btnCancel = confirmModal.querySelector('.btn-cancel');
|
||||
const btnConfirm = confirmModal.querySelector('.btn-confirm');
|
||||
|
||||
// CSS 변수 설정
|
||||
if (theme_color) {
|
||||
moduleElement.style.setProperty('--survey-primary', theme_color);
|
||||
moduleElement.style.setProperty('--survey-primary-light', theme_color + '20');
|
||||
moduleElement.style.setProperty('--survey-primary-dark', theme_color + 'CC');
|
||||
}
|
||||
|
||||
// 질문 렌더링
|
||||
function renderQuestions() {
|
||||
if (!questions || !questions.length) return;
|
||||
|
||||
const questionsHTML = questions.map((question, index) => {
|
||||
const fieldName = `answer_${question.sq_id}`;
|
||||
const required = question.sq_required ? 'required' : '';
|
||||
const requiredMark = question.sq_required ? '<span class="question-required">*</span>' : '';
|
||||
|
||||
let inputHTML = '';
|
||||
|
||||
switch (question.sq_type) {
|
||||
case 'text':
|
||||
inputHTML = `
|
||||
<input type="text"
|
||||
name="${fieldName}"
|
||||
class="form-input"
|
||||
placeholder="답변을 입력해주세요"
|
||||
${required}>
|
||||
`;
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
inputHTML = `
|
||||
<textarea name="${fieldName}"
|
||||
class="form-input form-textarea"
|
||||
placeholder="자세한 답변을 입력해주세요"
|
||||
${required}></textarea>
|
||||
`;
|
||||
break;
|
||||
|
||||
case 'radio':
|
||||
if (question.sq_options && Array.isArray(question.sq_options)) {
|
||||
inputHTML = `
|
||||
<div class="radio-group">
|
||||
${question.sq_options.map((option, optionIndex) => `
|
||||
<div class="radio-item">
|
||||
<input type="radio"
|
||||
name="${fieldName}"
|
||||
value="${escapeHtml(option)}"
|
||||
id="${fieldName}_${optionIndex}"
|
||||
${required}>
|
||||
<label for="${fieldName}_${optionIndex}">
|
||||
${escapeHtml(option)}
|
||||
</label>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
if (question.sq_options && Array.isArray(question.sq_options)) {
|
||||
inputHTML = `
|
||||
<div class="checkbox-group">
|
||||
${question.sq_options.map((option, optionIndex) => `
|
||||
<div class="checkbox-item">
|
||||
<input type="checkbox"
|
||||
name="${fieldName}[]"
|
||||
value="${escapeHtml(option)}"
|
||||
id="${fieldName}_${optionIndex}">
|
||||
<label for="${fieldName}_${optionIndex}">
|
||||
${escapeHtml(option)}
|
||||
</label>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
if (question.sq_options && Array.isArray(question.sq_options)) {
|
||||
inputHTML = `
|
||||
<select name="${fieldName}" class="form-select" ${required}>
|
||||
<option value="">선택해주세요</option>
|
||||
${question.sq_options.map(option => `
|
||||
<option value="${escapeHtml(option)}">
|
||||
${escapeHtml(option)}
|
||||
</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
`;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'rating':
|
||||
const scale = question.sq_options?.scale || 5;
|
||||
const labels = question.sq_options?.labels || [];
|
||||
inputHTML = `
|
||||
<div class="rating-container">
|
||||
${Array.from({ length: scale }, (_, i) => i + 1).map(value => `
|
||||
<div class="rating-item" data-value="${value}">
|
||||
<input type="radio"
|
||||
name="${fieldName}"
|
||||
value="${value}"
|
||||
id="${fieldName}_${value}"
|
||||
style="display: none;"
|
||||
${required}>
|
||||
<div class="rating-number">${value}</div>
|
||||
${labels[value - 1] ? `<div class="rating-label">${escapeHtml(labels[value - 1])}</div>` : ''}
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
inputHTML = `
|
||||
<input type="date"
|
||||
name="${fieldName}"
|
||||
class="form-date"
|
||||
${required}>
|
||||
`;
|
||||
break;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="question-container" data-question="${index + 1}">
|
||||
<div class="question-header">
|
||||
<span class="question-number">${index + 1}</span>
|
||||
<h3 class="question-title">
|
||||
${escapeHtml(question.sq_title)}
|
||||
${requiredMark}
|
||||
</h3>
|
||||
|
||||
${question.sq_description ? `
|
||||
<p class="question-description">${escapeHtml(question.sq_description)}</p>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
<div class="question-input">
|
||||
${inputHTML}
|
||||
<div class="error-message" id="error_${question.sq_id}"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
questionsContainer.innerHTML = questionsHTML;
|
||||
}
|
||||
|
||||
// HTML 이스케이프 함수
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// 진행률 업데이트
|
||||
function updateProgress() {
|
||||
let answeredQuestions = 0;
|
||||
const totalQuestions = questions.length;
|
||||
|
||||
questions.forEach((question, index) => {
|
||||
const questionContainer = questionsContainer.children[index];
|
||||
if (!questionContainer) return;
|
||||
|
||||
const inputs = questionContainer.querySelectorAll('input, textarea, select');
|
||||
let hasAnswer = false;
|
||||
|
||||
inputs.forEach(input => {
|
||||
if (input.type === 'radio' || input.type === 'checkbox') {
|
||||
if (input.checked) hasAnswer = true;
|
||||
} else if (input.value.trim() !== '') {
|
||||
hasAnswer = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasAnswer) {
|
||||
answeredQuestions++;
|
||||
}
|
||||
});
|
||||
|
||||
const progress = Math.round((answeredQuestions / totalQuestions) * 100);
|
||||
progressFill.style.width = progress + '%';
|
||||
progressText.textContent = progress + '%';
|
||||
currentQuestionSpan.textContent = answeredQuestions;
|
||||
|
||||
// 모든 필수 질문이 답변되었는지 확인
|
||||
const requiredQuestions = questionsContainer.querySelectorAll('input[required], textarea[required], select[required]');
|
||||
let allRequiredAnswered = true;
|
||||
|
||||
requiredQuestions.forEach(input => {
|
||||
if (input.type === 'radio') {
|
||||
const radioGroup = questionsContainer.querySelectorAll(`input[name="${input.name}"]`);
|
||||
let radioChecked = false;
|
||||
radioGroup.forEach(radio => {
|
||||
if (radio.checked) radioChecked = true;
|
||||
});
|
||||
if (!radioChecked) allRequiredAnswered = false;
|
||||
} else if (input.type === 'checkbox') {
|
||||
const checkboxGroup = questionsContainer.querySelectorAll(`input[name="${input.name}"]`);
|
||||
let checkboxChecked = false;
|
||||
checkboxGroup.forEach(checkbox => {
|
||||
if (checkbox.checked) checkboxChecked = true;
|
||||
});
|
||||
if (!checkboxChecked) allRequiredAnswered = false;
|
||||
} else if (input.value.trim() === '') {
|
||||
allRequiredAnswered = false;
|
||||
}
|
||||
});
|
||||
|
||||
submitBtn.disabled = !allRequiredAnswered;
|
||||
}
|
||||
|
||||
// 이벤트 리스너 바인딩
|
||||
function bindEvents() {
|
||||
// 라디오/체크박스 스타일링
|
||||
questionsContainer.addEventListener('click', (e) => {
|
||||
const radioItem = e.target.closest('.radio-item');
|
||||
const checkboxItem = e.target.closest('.checkbox-item');
|
||||
|
||||
if (radioItem) {
|
||||
const input = radioItem.querySelector('input');
|
||||
const groupName = input.name;
|
||||
|
||||
// 라디오 버튼 그룹의 다른 선택 해제
|
||||
questionsContainer.querySelectorAll(`input[name="${groupName}"]`).forEach(radio => {
|
||||
radio.closest('.radio-item').classList.remove('selected');
|
||||
});
|
||||
|
||||
input.checked = true;
|
||||
radioItem.classList.add('selected');
|
||||
updateProgress();
|
||||
}
|
||||
|
||||
if (checkboxItem) {
|
||||
const input = checkboxItem.querySelector('input');
|
||||
input.checked = !input.checked;
|
||||
checkboxItem.classList.toggle('selected', input.checked);
|
||||
updateProgress();
|
||||
}
|
||||
});
|
||||
|
||||
// 평점 클릭 이벤트
|
||||
questionsContainer.addEventListener('click', (e) => {
|
||||
const ratingItem = e.target.closest('.rating-item');
|
||||
if (ratingItem) {
|
||||
const value = ratingItem.dataset.value;
|
||||
const input = ratingItem.querySelector('input');
|
||||
const container = ratingItem.closest('.rating-container');
|
||||
|
||||
// 같은 그룹의 다른 평점 해제
|
||||
container.querySelectorAll('.rating-item').forEach(item => {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
|
||||
// 현재 평점 선택
|
||||
ratingItem.classList.add('selected');
|
||||
input.checked = true;
|
||||
|
||||
updateProgress();
|
||||
}
|
||||
});
|
||||
|
||||
// 일반 입력 필드 이벤트
|
||||
questionsContainer.addEventListener('input', updateProgress);
|
||||
questionsContainer.addEventListener('change', updateProgress);
|
||||
|
||||
// 폼 제출 이벤트
|
||||
surveyForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (submitBtn.disabled) {
|
||||
showNotification('모든 필수 항목을 입력해주세요.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 확인 모달 표시
|
||||
showConfirmModal();
|
||||
});
|
||||
|
||||
// 모달 이벤트
|
||||
modalClose.addEventListener('click', hideConfirmModal);
|
||||
btnCancel.addEventListener('click', hideConfirmModal);
|
||||
modalOverlay.addEventListener('click', hideConfirmModal);
|
||||
|
||||
btnConfirm.addEventListener('click', () => {
|
||||
hideConfirmModal();
|
||||
submitSurvey();
|
||||
});
|
||||
|
||||
// ESC 키로 모달 닫기
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && confirmModal.classList.contains('show')) {
|
||||
hideConfirmModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 확인 모달 표시
|
||||
function showConfirmModal() {
|
||||
confirmModal.classList.add('show');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
// 확인 모달 숨기기
|
||||
function hideConfirmModal() {
|
||||
confirmModal.classList.remove('show');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// 설문 제출
|
||||
function submitSurvey() {
|
||||
submitBtn.classList.add('loading');
|
||||
submitBtn.innerHTML = '<div class="loading-spinner"></div> 제출 중...';
|
||||
submitBtn.disabled = true;
|
||||
|
||||
const formData = new FormData(surveyForm);
|
||||
formData.append('ajax', '1');
|
||||
|
||||
fetch(surveyForm.action, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showNotification('설문이 성공적으로 제출되었습니다!', 'success');
|
||||
setTimeout(() => {
|
||||
window.location.href = data.redirect_url;
|
||||
}, 1500);
|
||||
} else {
|
||||
showNotification(data.errors ? data.errors.join('\n') : '제출 중 오류가 발생했습니다.', 'error');
|
||||
submitBtn.classList.remove('loading');
|
||||
submitBtn.innerHTML = '<i class="fa fa-paper-plane"></i> 설문 제출하기';
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('제출 중 오류가 발생했습니다.', 'error');
|
||||
submitBtn.classList.remove('loading');
|
||||
submitBtn.innerHTML = '<i class="fa fa-paper-plane"></i> 설문 제출하기';
|
||||
submitBtn.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 알림 표시
|
||||
function showNotification(message, type = 'info') {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `survey-notification survey-notification-${type}`;
|
||||
notification.innerHTML = `
|
||||
<div class="notification-content">
|
||||
<i class="fa fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
|
||||
<span>${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 스타일 추가
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: ${type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#17a2b8'};
|
||||
color: white;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
z-index: 1060;
|
||||
animation: slideInRight 0.3s ease;
|
||||
max-width: 300px;
|
||||
word-wrap: break-word;
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.animation = 'slideOutRight 0.3s ease';
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 300);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// 스크롤 시 질문 하이라이트
|
||||
function initScrollHighlight() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
// 모든 하이라이트 제거
|
||||
questionsContainer.querySelectorAll('.question-container').forEach(q => {
|
||||
q.classList.remove('highlight');
|
||||
});
|
||||
// 현재 질문 하이라이트
|
||||
entry.target.classList.add('highlight');
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.5,
|
||||
rootMargin: '-20% 0px -20% 0px'
|
||||
});
|
||||
|
||||
questionsContainer.querySelectorAll('.question-container').forEach(question => {
|
||||
observer.observe(question);
|
||||
});
|
||||
}
|
||||
|
||||
// 질문 애니메이션 초기화
|
||||
function initQuestionAnimations() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.opacity = '1';
|
||||
entry.target.style.animationPlayState = 'running';
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
});
|
||||
|
||||
questionsContainer.querySelectorAll('.question-container').forEach(question => {
|
||||
question.style.opacity = '0';
|
||||
question.style.animationPlayState = 'paused';
|
||||
observer.observe(question);
|
||||
});
|
||||
}
|
||||
|
||||
// 초기화
|
||||
function init() {
|
||||
renderQuestions();
|
||||
bindEvents();
|
||||
updateProgress();
|
||||
initScrollHighlight();
|
||||
initQuestionAnimations();
|
||||
|
||||
moduleElement.classList.add('initialized');
|
||||
}
|
||||
|
||||
// 모듈 초기화 실행
|
||||
init();
|
||||
}
|
||||
|
||||
// 추가 CSS 애니메이션 (JavaScript로 동적 추가)
|
||||
const additionalStyles = `
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutRight {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.survey-notification .notification-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.survey-notification i {
|
||||
font-size: 1.2em;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
// 스타일 추가 (한 번만)
|
||||
if (!document.getElementById('survey-form-module-styles')) {
|
||||
const styleSheet = document.createElement('style');
|
||||
styleSheet.id = 'survey-form-module-styles';
|
||||
styleSheet.textContent = additionalStyles;
|
||||
document.head.appendChild(styleSheet);
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// 설문 관리 라이브러리 로드
|
||||
$survey_lib_path = G5_ADMIN_PATH.'/survey_manage/lib/survey.lib.php';
|
||||
if (!file_exists($survey_lib_path)) {
|
||||
echo '<div class="alert alert-danger">설문 라이브러리 파일이 없습니다.</div>';
|
||||
return;
|
||||
}
|
||||
include_once($survey_lib_path);
|
||||
|
||||
// 모듈 설정에서 설문 ID 가져오기 (rb.custom 모듈 방식)
|
||||
$sv_id = 0;
|
||||
|
||||
// 1. 모듈 설정에서 sv_id 확인 (rb_module 테이블의 설정값)
|
||||
if (isset($row_mod['md_custom_survey_key']) && $row_mod['md_custom_survey_key']) {
|
||||
$sv_id = (int)$row_mod['md_custom_survey_key'];
|
||||
}
|
||||
|
||||
// 2. URL 파라미터에서 sv_id 확인 (우선순위 높음)
|
||||
if (isset($_GET['sv_id']) && $_GET['sv_id']) {
|
||||
$sv_id = (int)$_GET['sv_id'];
|
||||
}
|
||||
else if (isset($_POST['sv_id']) && $_POST['sv_id']) {
|
||||
$sv_id = (int)$_POST['sv_id'];
|
||||
}
|
||||
|
||||
|
||||
// sv_id가 없으면 설문 선택 인터페이스 표시
|
||||
if (!$sv_id && $sv_id == 0) {
|
||||
echo '<div class="survey-form-module">';
|
||||
echo '<div class="survey-container">';
|
||||
echo '<div class="survey-header">';
|
||||
echo '<div class="container">';
|
||||
echo '<h3>설문을 선택해주세요</h3>';
|
||||
echo '<p>모듈 설정에서 설문을 선택하거나, URL에 ?sv_id=설문번호를 추가하여 특정 설문을 표시할 수 있습니다.</p>';
|
||||
|
||||
// 모든 설문 목록 표시 (관리자용)
|
||||
if ($is_admin) {
|
||||
$all_surveys = sql_query("SELECT sv_id, sv_title, sv_status, sv_start_date, sv_end_date FROM survey_master ORDER BY sv_created_at DESC LIMIT 10");
|
||||
|
||||
if (sql_num_rows($all_surveys) > 0) {
|
||||
echo '<div class="survey-list admin-survey-list">';
|
||||
echo '<h4>설문 목록 (관리자 전용):</h4>';
|
||||
echo '<div class="survey-grid">';
|
||||
while ($survey_item = sql_fetch_array($all_surveys)) {
|
||||
$status_class = '';
|
||||
$status_text = '';
|
||||
switch($survey_item['sv_status']) {
|
||||
case 'active': $status_class = 'status-active'; $status_text = '진행중'; break;
|
||||
case 'draft': $status_class = 'status-draft'; $status_text = '임시저장'; break;
|
||||
case 'closed': $status_class = 'status-closed'; $status_text = '종료'; break;
|
||||
default: $status_class = 'status-default'; $status_text = $survey_item['sv_status']; break;
|
||||
}
|
||||
|
||||
echo '<div class="survey-card">';
|
||||
echo '<div class="survey-card-header">';
|
||||
echo '<h5><a href="?sv_id='.$survey_item['sv_id'].'">'.$survey_item['sv_title'].'</a></h5>';
|
||||
echo '<span class="survey-status '.$status_class.'">'.$status_text.'</span>';
|
||||
echo '</div>';
|
||||
echo '<div class="survey-card-body">';
|
||||
echo '<p>기간: '.date('Y-m-d', strtotime($survey_item['sv_start_date'])).' ~ '.date('Y-m-d', strtotime($survey_item['sv_end_date'])).'</p>';
|
||||
echo '<a href="?sv_id='.$survey_item['sv_id'].'" class="btn-view-survey">설문 보기</a>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
} else {
|
||||
// 일반 사용자용 - 활성화된 설문만 표시
|
||||
$active_surveys = sql_query("SELECT sv_id, sv_title, sv_description FROM survey_master WHERE sv_status = 'active' AND sv_start_date <= NOW() AND sv_end_date >= NOW() ORDER BY sv_created_at DESC LIMIT 5");
|
||||
|
||||
if (sql_num_rows($active_surveys) > 0) {
|
||||
echo '<div class="survey-list">';
|
||||
echo '<h4>현재 진행 중인 설문:</h4>';
|
||||
echo '<div class="survey-grid">';
|
||||
while ($survey_item = sql_fetch_array($active_surveys)) {
|
||||
echo '<div class="survey-card">';
|
||||
echo '<div class="survey-card-header">';
|
||||
echo '<h5><a href="?sv_id='.$survey_item['sv_id'].'">'.$survey_item['sv_title'].'</a></h5>';
|
||||
echo '</div>';
|
||||
if ($survey_item['sv_description']) {
|
||||
echo '<div class="survey-card-body">';
|
||||
echo '<p>'.htmlspecialchars(mb_substr($survey_item['sv_description'], 0, 100)).'...</p>';
|
||||
echo '<a href="?sv_id='.$survey_item['sv_id'].'" class="btn-view-survey">참여하기</a>';
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<div class="no-surveys">';
|
||||
echo '<i class="fa fa-clipboard" style="font-size: 3em; color: #ddd; margin-bottom: 15px;"></i>';
|
||||
echo '<p>현재 진행 중인 설문이 없습니다.</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div></div></div></div>';
|
||||
|
||||
// 기본 스타일 추가
|
||||
echo '<style>
|
||||
.survey-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 15px; margin-top: 15px; }
|
||||
.survey-card { border: 1px solid #ddd; border-radius: 8px; padding: 15px; background: white; }
|
||||
.survey-card-header { margin-bottom: 10px; }
|
||||
.survey-card-header h5 { margin: 0 0 5px 0; }
|
||||
.survey-card-header a { color: #333; text-decoration: none; }
|
||||
.survey-card-header a:hover { color: #AA20FF; }
|
||||
.survey-status { padding: 3px 8px; border-radius: 12px; font-size: 0.8em; }
|
||||
.status-active { background: #d4edda; color: #155724; }
|
||||
.status-draft { background: #fff3cd; color: #856404; }
|
||||
.status-closed { background: #f8d7da; color: #721c24; }
|
||||
.btn-view-survey { display: inline-block; padding: 8px 15px; background: #AA20FF; color: white; text-decoration: none; border-radius: 4px; font-size: 0.9em; }
|
||||
.btn-view-survey:hover { background: #8A1ACC; color: white; }
|
||||
.no-surveys { text-align: center; padding: 40px; color: #666; }
|
||||
</style>';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 함수 존재 확인
|
||||
if (!function_exists('validate_survey_access')) {
|
||||
echo '<div class="alert alert-danger">설문 검증 함수가 정의되지 않았습니다.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 설문 유효성 검사
|
||||
$validation = validate_survey_access($sv_id, $member['mb_id'], $_SERVER['REMOTE_ADDR']);
|
||||
if (!$validation['success']) {
|
||||
echo '<div class="alert alert-warning">'.$validation['message'].'</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$survey = $validation['survey'];
|
||||
$questions = get_survey_questions($sv_id);
|
||||
|
||||
if (empty($questions)) {
|
||||
echo '<div class="alert alert-info">이 설문에는 아직 질문이 등록되지 않았습니다.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 설문 테마 색상
|
||||
$theme_color = $survey['sv_theme_color'] ?: '#AA20FF';
|
||||
|
||||
// 설문 데이터를 JSON으로 준비
|
||||
$survey_data = array(
|
||||
'survey' => $survey,
|
||||
'questions' => $questions,
|
||||
'theme_color' => $theme_color,
|
||||
'total_responses' => get_survey_response_count($sv_id, 'completed')
|
||||
);
|
||||
|
||||
$survey_json = json_encode($survey_data, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// CSS와 JS 파일의 버전을 파일 수정 시간으로 자동 갱신
|
||||
$module_css_path = G5_THEME_PATH.'/rb.custom/survey_form/module.css';
|
||||
$module_js_path = G5_THEME_PATH.'/rb.custom/survey_form/module.js';
|
||||
$module_css_ver = file_exists($module_css_path) ? filemtime($module_css_path) : G5_CSS_VER;
|
||||
$module_js_ver = file_exists($module_js_path) ? filemtime($module_js_path) : G5_JS_VER;
|
||||
// 이 모듈만의 고유 ID를 생성합니다.
|
||||
$module_id = 'survey_form_module_'.uniqid();
|
||||
?>
|
||||
|
||||
<!-- 모듈의 가장 바깥 요소에 고유 ID를 부여합니다. -->
|
||||
<div id="<?php echo $module_id; ?>" class="survey-form-module" data-survey='<?php echo htmlspecialchars($survey_json, ENT_QUOTES, 'UTF-8'); ?>'>
|
||||
<div class="survey-container">
|
||||
<!-- 설문 헤더 -->
|
||||
<div class="survey-header">
|
||||
<div class="container">
|
||||
<h1 class="survey-title"><?php echo htmlspecialchars($survey['sv_title']); ?></h1>
|
||||
<?php if ($survey['sv_description']): ?>
|
||||
<p class="survey-description"><?php echo nl2br(htmlspecialchars($survey['sv_description'])); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="survey-info">
|
||||
<div class="survey-info-item">
|
||||
<i class="fa fa-clock"></i>
|
||||
<span>예상 소요시간: <span class="estimated-time"><?php echo count($questions); ?>분</span></span>
|
||||
</div>
|
||||
<div class="survey-info-item">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
<span>총 <span class="total-questions"><?php echo count($questions); ?></span>개 질문</span>
|
||||
</div>
|
||||
<div class="survey-info-item">
|
||||
<i class="fa fa-users"></i>
|
||||
<span><span class="total-participants"><?php echo number_format(get_survey_response_count($sv_id, 'completed')); ?></span>명 참여</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 진행률 바 -->
|
||||
<div class="progress-container">
|
||||
<div class="container">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="progressFill"></div>
|
||||
</div>
|
||||
<div class="progress-text">
|
||||
<span id="progressText">0%</span> 완료 (<span id="currentQuestion">0</span> / <span class="total-questions"><?php echo count($questions); ?></span>)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설문 폼 -->
|
||||
<div class="survey-form-container">
|
||||
<div class="container">
|
||||
<form id="surveyForm" class="survey-form" method="post" action="<?php echo G5_THEME_URL; ?>/rb.custom/survey_form/survey_submit_page.php">
|
||||
<input type="hidden" name="sv_id" value="<?php echo $sv_id; ?>">
|
||||
|
||||
<div class="questions-container" id="questionsContainer">
|
||||
<!-- JavaScript로 질문들이 동적으로 생성됩니다 -->
|
||||
</div>
|
||||
|
||||
<div class="submit-container">
|
||||
<button type="submit" class="submit-btn" id="submitBtn" disabled>
|
||||
<i class="fa fa-paper-plane"></i> 설문 제출하기
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 확인 모달 -->
|
||||
<div class="confirm-modal">
|
||||
<div class="modal-overlay"></div>
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>설문 제출 확인</h3>
|
||||
<button type="button" class="modal-close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>설문을 제출하시겠습니까?</p>
|
||||
<p class="modal-warning">제출 후에는 수정할 수 없습니다.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn-cancel">취소</button>
|
||||
<button type="button" class="btn-confirm">제출하기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 모듈에 필요한 CSS 파일을 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/survey_form/module.css?ver=<?php echo $module_css_ver; ?>">
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const currentModuleId = '<?php echo $module_id; ?>';
|
||||
const initFunctionName = 'initSurveyFormModule';
|
||||
const scriptId = 'survey-form-module-script';
|
||||
|
||||
if (document.getElementById(scriptId)) {
|
||||
if (typeof window[initFunctionName] === 'function') {
|
||||
window[initFunctionName](currentModuleId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.src = '<?php echo G5_THEME_URL; ?>/rb.custom/survey_form/module.js?ver=<?php echo $module_js_ver; ?>';
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
if (typeof window[initFunctionName] === 'function') {
|
||||
window[initFunctionName](currentModuleId);
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,563 @@
|
||||
<?php
|
||||
include_once('../../_common.php');
|
||||
|
||||
// 설문 관리 라이브러리 로드
|
||||
include_once(G5_ADMIN_PATH . '/survey_manage/lib/survey.lib.php');
|
||||
|
||||
$sv_id = isset($_GET['sv_id']) ? (int)$_GET['sv_id'] : 0;
|
||||
$sr_id = isset($_GET['sr_id']) ? (int)$_GET['sr_id'] : 0;
|
||||
|
||||
if (!$sv_id || !$sr_id) {
|
||||
alert('잘못된 접근입니다.', G5_URL);
|
||||
}
|
||||
|
||||
$survey = get_survey($sv_id);
|
||||
if (!$survey) {
|
||||
alert('존재하지 않는 설문입니다.', G5_URL);
|
||||
}
|
||||
|
||||
// 응답 확인
|
||||
$response = sql_fetch("SELECT * FROM survey_responses WHERE sr_id = '$sr_id' AND sv_id = '$sv_id'");
|
||||
if (!$response || $response['sr_status'] !== 'completed') {
|
||||
alert('완료되지 않은 응답입니다.', G5_URL);
|
||||
}
|
||||
|
||||
$g5['title'] = '설문 완료 - ' . $survey['sv_title'];
|
||||
include_once(G5_THEME_PATH . '/head.sub.php');
|
||||
|
||||
// 설문 테마 색상
|
||||
$theme_color = $survey['sv_theme_color'] ?: '#AA20FF';
|
||||
|
||||
// 응답 통계
|
||||
$total_responses = get_survey_response_count($sv_id, 'completed');
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* 페이지 전용 스타일 */
|
||||
:root {
|
||||
--survey-primary: <?php echo $theme_color; ?>;
|
||||
--survey-primary-light: <?php echo $theme_color; ?>20;
|
||||
--survey-primary-dark: <?php echo $theme_color; ?>CC;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(135deg, var(--survey-primary-light) 0%, #ffffff 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.complete-page-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100px 20px 20px;
|
||||
}
|
||||
|
||||
.complete-card {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 60px 40px;
|
||||
text-align: center;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
animation: slideInUp 0.8s ease;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.complete-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 5px;
|
||||
background: linear-gradient(90deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: var(--survey-primary);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 30px;
|
||||
animation: bounceIn 1s ease 0.3s both;
|
||||
}
|
||||
|
||||
.success-icon i {
|
||||
font-size: 3em;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.complete-title {
|
||||
font-size: 2.5em;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
animation: fadeInUp 0.8s ease 0.5s both;
|
||||
}
|
||||
|
||||
.complete-message {
|
||||
font-size: 1.2em;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 30px;
|
||||
animation: fadeInUp 0.8s ease 0.7s both;
|
||||
}
|
||||
|
||||
.thank-message {
|
||||
background: var(--survey-primary-light);
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin: 30px 0;
|
||||
font-style: italic;
|
||||
color: var(--survey-primary-dark);
|
||||
animation: fadeInUp 0.8s ease 0.9s both;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 30px;
|
||||
margin: 40px 0;
|
||||
animation: fadeInUp 0.8s ease 1.1s both;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: var(--survey-primary);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
animation: fadeInUp 0.8s ease 1.3s both;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 15px 30px;
|
||||
border-radius: 50px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--survey-primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: var(--survey-primary);
|
||||
border: 2px solid var(--survey-primary);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.social-share {
|
||||
margin-top: 30px;
|
||||
padding-top: 30px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
animation: fadeInUp 0.8s ease 1.5s both;
|
||||
}
|
||||
|
||||
.social-share h4 {
|
||||
color: #666;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.social-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.social-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.social-btn:hover {
|
||||
transform: scale(1.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.social-facebook {
|
||||
background: #3b5998;
|
||||
}
|
||||
|
||||
.social-twitter {
|
||||
background: #1da1f2;
|
||||
}
|
||||
|
||||
.social-kakao {
|
||||
background: #fee500;
|
||||
color: #3c1e1e;
|
||||
}
|
||||
|
||||
.social-line {
|
||||
background: #00c300;
|
||||
}
|
||||
|
||||
/* 파티클 효과 */
|
||||
.particles {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.particle {
|
||||
position: absolute;
|
||||
background: var(--survey-primary);
|
||||
border-radius: 50%;
|
||||
opacity: 0.6;
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.particle:nth-child(1) {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
left: 10%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.particle:nth-child(2) {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
left: 20%;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
.particle:nth-child(3) {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
left: 30%;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.particle:nth-child(4) {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
left: 40%;
|
||||
animation-delay: 3s;
|
||||
}
|
||||
|
||||
.particle:nth-child(5) {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
left: 50%;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.particle:nth-child(6) {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
left: 60%;
|
||||
animation-delay: 5s;
|
||||
}
|
||||
|
||||
.particle:nth-child(7) {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
left: 70%;
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
.particle:nth-child(8) {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
left: 80%;
|
||||
animation-delay: 1.5s;
|
||||
}
|
||||
|
||||
.particle:nth-child(9) {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
left: 90%;
|
||||
animation-delay: 2.5s;
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.complete-page-container {
|
||||
padding: 80px 10px 20px;
|
||||
}
|
||||
|
||||
.complete-card {
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.complete-title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 애니메이션 */
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(50px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounceIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
70% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(100vh) rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
10%, 90% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px) rotate(180deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="complete-page-container">
|
||||
<div class="complete-card">
|
||||
<!-- 파티클 효과 -->
|
||||
<div class="particles">
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
<div class="particle"></div>
|
||||
</div>
|
||||
|
||||
<!-- 성공 아이콘 -->
|
||||
<div class="success-icon">
|
||||
<i class="fa fa-check"></i>
|
||||
</div>
|
||||
|
||||
<!-- 완료 메시지 -->
|
||||
<h1 class="complete-title">설문 완료!</h1>
|
||||
<p class="complete-message">
|
||||
<strong><?php echo htmlspecialchars($survey['sv_title']); ?></strong><br>
|
||||
설문에 참여해 주셔서 감사합니다.
|
||||
</p>
|
||||
|
||||
<!-- 감사 메시지 -->
|
||||
<?php if ($survey['sv_thank_message']): ?>
|
||||
<div class="thank-message">
|
||||
<?php echo nl2br(htmlspecialchars($survey['sv_thank_message'])); ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="thank-message">
|
||||
소중한 의견을 주셔서 감사합니다.<br>
|
||||
더 나은 서비스를 위해 활용하겠습니다.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 통계 정보 -->
|
||||
<div class="stats-container">
|
||||
<div class="stat-item">
|
||||
<span class="stat-number"><?php echo number_format($total_responses); ?></span>
|
||||
<div class="stat-label">총 참여자 수</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-number"><?php echo $response['sr_id']; ?></span>
|
||||
<div class="stat-label">응답 번호</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 액션 버튼 -->
|
||||
<div class="action-buttons">
|
||||
<a href="<?php echo G5_URL; ?>" class="btn btn-primary">
|
||||
<i class="fa fa-home"></i> 홈으로 이동
|
||||
</a>
|
||||
<!-- <a href="survey_list_page.php" class="btn btn-outline">-->
|
||||
<!-- <i class="fa fa-list"></i> 다른 설문 보기-->
|
||||
<!-- </a>-->
|
||||
</div>
|
||||
|
||||
<!-- 소셜 공유 -->
|
||||
<div class="social-share">
|
||||
<h4>설문을 공유해보세요</h4>
|
||||
<div class="social-buttons">
|
||||
<a href="#" class="social-btn social-facebook" onclick="shareToFacebook()" title="페이스북 공유">
|
||||
<i class="fab fa-facebook-f"></i>
|
||||
</a>
|
||||
<a href="#" class="social-btn social-twitter" onclick="shareToTwitter()" title="트위터 공유">
|
||||
<i class="fab fa-twitter"></i>
|
||||
</a>
|
||||
<a href="#" class="social-btn social-kakao" onclick="shareToKakao()" title="카카오톡 공유">
|
||||
<i class="fab fa-comment"></i>
|
||||
</a>
|
||||
<a href="#" class="social-btn social-line" onclick="shareToLine()" title="라인 공유">
|
||||
<i class="fab fa-line"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 소셜 공유 함수들
|
||||
function shareToFacebook() {
|
||||
const url = encodeURIComponent(window.location.origin + '/theme/rd.lwd/survey_page.php?sv_id=<?php echo $sv_id; ?>');
|
||||
const title = encodeURIComponent('<?php echo addslashes($survey['sv_title']); ?>');
|
||||
window.open(`https://www.facebook.com/sharer/sharer.php?u=${url}`, '_blank', 'width=600,height=400');
|
||||
}
|
||||
|
||||
function shareToTwitter() {
|
||||
const url = encodeURIComponent(window.location.origin + '/theme/rd.lwd/survey_page.php?sv_id=<?php echo $sv_id; ?>');
|
||||
const text = encodeURIComponent('<?php echo addslashes($survey['sv_title']); ?> 설문에 참여해보세요!');
|
||||
window.open(`https://twitter.com/intent/tweet?url=${url}&text=${text}`, '_blank', 'width=600,height=400');
|
||||
}
|
||||
|
||||
function shareToKakao() {
|
||||
// 카카오톡 공유 (실제 구현시 카카오 SDK 필요)
|
||||
alert('카카오톡 공유 기능은 카카오 개발자 등록 후 사용 가능합니다.');
|
||||
}
|
||||
|
||||
function shareToLine() {
|
||||
const url = encodeURIComponent(window.location.origin + '/theme/rd.lwd/survey_page.php?sv_id=<?php echo $sv_id; ?>');
|
||||
const text = encodeURIComponent('<?php echo addslashes($survey['sv_title']); ?>');
|
||||
window.open(`https://social-plugins.line.me/lineit/share?url=${url}&text=${text}`, '_blank', 'width=600,height=400');
|
||||
}
|
||||
|
||||
// 페이지 로드 시 축하 효과
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// 3초 후 파티클 효과 시작
|
||||
setTimeout(() => {
|
||||
document.querySelector('.particles').style.display = 'block';
|
||||
}, 1000);
|
||||
|
||||
// 성공 사운드 효과 (선택사항)
|
||||
// playSuccessSound();
|
||||
});
|
||||
|
||||
// 성공 사운드 재생 함수 (선택사항)
|
||||
function playSuccessSound() {
|
||||
// Web Audio API를 사용한 간단한 성공 사운드
|
||||
try {
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const oscillator = audioContext.createOscillator();
|
||||
const gainNode = audioContext.createGain();
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(audioContext.destination);
|
||||
|
||||
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
|
||||
oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime + 0.1); // E5
|
||||
oscillator.frequency.setValueAtTime(783.99, audioContext.currentTime + 0.2); // G5
|
||||
|
||||
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
|
||||
|
||||
oscillator.start(audioContext.currentTime);
|
||||
oscillator.stop(audioContext.currentTime + 0.5);
|
||||
} catch (e) {
|
||||
// 오디오 컨텍스트 생성 실패시 무시
|
||||
console.log('Audio context not supported');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php
|
||||
include_once(G5_THEME_PATH . '/tail.sub.php');
|
||||
?>
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
//if (!defined('_GNUBOARD_')) exit;
|
||||
include_once('../../../../common.php');
|
||||
|
||||
// 설문 관리 라이브러리 로드
|
||||
include_once(G5_ADMIN_PATH.'/survey_manage/lib/survey.lib.php');
|
||||
|
||||
$sv_id = isset($_GET['sv_id']) ? (int)$_GET['sv_id'] : 0;
|
||||
|
||||
if (!$sv_id) {
|
||||
alert('잘못된 접근입니다.', G5_URL);
|
||||
}
|
||||
|
||||
// 설문 유효성 검사
|
||||
$validation = validate_survey_access($sv_id, $member['mb_id'], $_SERVER['REMOTE_ADDR']);
|
||||
if (!$validation['success']) {
|
||||
alert($validation['message']);
|
||||
return;
|
||||
}
|
||||
|
||||
$survey = $validation['survey'];
|
||||
$questions = get_survey_questions($sv_id);
|
||||
|
||||
if (empty($questions)) {
|
||||
alert('설문 질문이 없습니다.', G5_URL);
|
||||
}
|
||||
|
||||
$g5['title'] = $survey['sv_title'];
|
||||
include_once(G5_THEME_PATH.'/head.sub.php');
|
||||
|
||||
// 설문 테마 색상
|
||||
$theme_color = $survey['sv_theme_color'] ?: '#AA20FF';
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* 페이지 전용 스타일 */
|
||||
:root {
|
||||
--survey-primary: <?php echo $theme_color; ?>;
|
||||
--survey-primary-light: <?php echo $theme_color; ?>20;
|
||||
--survey-primary-dark: <?php echo $theme_color; ?>CC;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(135deg, var(--survey-primary-light) 0%, #ffffff 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.survey-page-container {
|
||||
min-height: 100vh;
|
||||
padding-top: 100px; /* 헤더 높이만큼 */
|
||||
}
|
||||
|
||||
.survey-page-header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
padding: 40px 20px;
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
max-width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.survey-page-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 5px;
|
||||
background: linear-gradient(90deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
}
|
||||
|
||||
.survey-page-title {
|
||||
font-size: 2.5em;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.survey-page-description {
|
||||
font-size: 1.1em;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.survey-page-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 30px;
|
||||
margin-top: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.survey-page-info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #888;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.survey-page-info-item i {
|
||||
color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.survey-form-section {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px 80px;
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.survey-page-container {
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
.survey-page-title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.survey-page-info {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.survey-form-section {
|
||||
padding: 0 10px 60px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="survey-page-container">
|
||||
<!-- 설문 헤더 -->
|
||||
<!-- <div class="survey-page-header">-->
|
||||
<!-- <h1 class="survey-page-title">--><?php //echo htmlspecialchars($survey['sv_title']); ?><!--</h1>-->
|
||||
<!-- --><?php //if ($survey['sv_description']): ?>
|
||||
<!-- <p class="survey-page-description">--><?php //echo nl2br(htmlspecialchars($survey['sv_description'])); ?><!--</p>-->
|
||||
<!-- --><?php //endif; ?>
|
||||
<!-- -->
|
||||
<!-- <div class="survey-page-info">-->
|
||||
<!-- <div class="survey-page-info-item">-->
|
||||
<!-- <i class="fa fa-clock"></i>-->
|
||||
<!-- <span>예상 소요시간: --><?php //echo count($questions); ?><!--분</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="survey-page-info-item">-->
|
||||
<!-- <i class="fa fa-question-circle"></i>-->
|
||||
<!-- <span>총 --><?php //echo count($questions); ?><!--개 질문</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="survey-page-info-item">-->
|
||||
<!-- <i class="fa fa-users"></i>-->
|
||||
<!-- <span>--><?php //echo number_format(get_survey_response_count($sv_id, 'completed')); ?><!--명 참여</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- 설문 폼 섹션 (rb.custom 모듈 사용) -->
|
||||
<div class="survey-form-section">
|
||||
<?php
|
||||
// 설문 폼 커스텀 모듈 포함
|
||||
$_GET['sv_id'] = $sv_id; // 모듈에서 사용할 수 있도록 설정
|
||||
include_once(G5_THEME_PATH.'/rb.custom/survey_form/module.php');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_THEME_PATH.'/tail.sub.php');
|
||||
?>
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
include_once('../../_common.php');
|
||||
|
||||
// 설문 관리 라이브러리 로드
|
||||
include_once(G5_ADMIN_PATH.'/survey_manage/lib/survey.lib.php');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
alert('잘못된 접근입니다.', G5_URL);
|
||||
}
|
||||
|
||||
$sv_id = isset($_POST['sv_id']) ? (int)$_POST['sv_id'] : 0;
|
||||
|
||||
if (!$sv_id) {
|
||||
alert('잘못된 접근입니다.', G5_URL);
|
||||
}
|
||||
|
||||
// 설문 유효성 검사
|
||||
$validation = validate_survey_access($sv_id, $member['mb_id'], $_SERVER['REMOTE_ADDR']);
|
||||
if (!$validation['success']) {
|
||||
alert($validation['message'], G5_URL);
|
||||
}
|
||||
|
||||
$survey = $validation['survey'];
|
||||
$questions = get_survey_questions($sv_id);
|
||||
|
||||
if (empty($questions)) {
|
||||
alert('설문 질문이 없습니다.', G5_URL);
|
||||
}
|
||||
|
||||
// 응답 시작
|
||||
$sr_id = start_survey_response(
|
||||
$sv_id,
|
||||
$member['mb_id'] ?: null,
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
$_SERVER['HTTP_USER_AGENT'] ?: '',
|
||||
session_id()
|
||||
);
|
||||
|
||||
if (!$sr_id) {
|
||||
alert('응답 저장 중 오류가 발생했습니다.', G5_URL);
|
||||
}
|
||||
|
||||
// 답변 저장
|
||||
$errors = array();
|
||||
foreach ($questions as $question) {
|
||||
$field_name = 'answer_' . $question['sq_id'];
|
||||
$value = isset($_POST[$field_name]) ? $_POST[$field_name] : '';
|
||||
|
||||
// 필수 질문 검증
|
||||
if ($question['sq_required']) {
|
||||
if (is_array($value)) {
|
||||
if (empty($value) || (count($value) == 1 && empty($value[0]))) {
|
||||
$errors[] = $question['sq_title'] . ' 항목은 필수입니다.';
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (empty(trim($value))) {
|
||||
$errors[] = $question['sq_title'] . ' 항목은 필수입니다.';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 유효성 검사
|
||||
if ($question['sq_validation'] && !empty($value)) {
|
||||
$validation_rules = $question['sq_validation'];
|
||||
|
||||
if (isset($validation_rules['minLength']) && strlen($value) < $validation_rules['minLength']) {
|
||||
$errors[] = $question['sq_title'] . ' 항목은 최소 ' . $validation_rules['minLength'] . '자 이상 입력해주세요.';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($validation_rules['maxLength']) && strlen($value) > $validation_rules['maxLength']) {
|
||||
$errors[] = $question['sq_title'] . ' 항목은 최대 ' . $validation_rules['maxLength'] . '자까지 입력 가능합니다.';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($validation_rules['pattern'])) {
|
||||
$pattern = $validation_rules['pattern'];
|
||||
if ($pattern === 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||
$errors[] = $question['sq_title'] . ' 항목에 올바른 이메일 주소를 입력해주세요.';
|
||||
continue;
|
||||
}
|
||||
if ($pattern === 'phone' && !preg_match('/^[0-9-+\s()]+$/', $value)) {
|
||||
$errors[] = $question['sq_title'] . ' 항목에 올바른 전화번호를 입력해주세요.';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 답변 저장
|
||||
if (!empty($value) || $question['sq_required']) {
|
||||
save_survey_answer($sr_id, $question['sq_id'], $value);
|
||||
}
|
||||
}
|
||||
|
||||
// 오류가 있으면 응답 삭제하고 돌아가기
|
||||
if (!empty($errors)) {
|
||||
sql_query("DELETE FROM survey_responses WHERE sr_id = '$sr_id'");
|
||||
|
||||
// JSON 응답인지 확인
|
||||
if (isset($_POST['ajax']) && $_POST['ajax'] == '1') {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(array(
|
||||
'success' => false,
|
||||
'errors' => $errors
|
||||
));
|
||||
exit;
|
||||
} else {
|
||||
alert(implode('\n', $errors), 'survey_page.php?sv_id=' . $sv_id);
|
||||
}
|
||||
}
|
||||
|
||||
// 응답 완료 처리
|
||||
complete_survey_response($sr_id);
|
||||
|
||||
// 통계 업데이트
|
||||
update_survey_statistics($sv_id);
|
||||
|
||||
// JSON 응답인지 확인
|
||||
if (isset($_POST['ajax']) && $_POST['ajax'] == '1') {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(array(
|
||||
'success' => true,
|
||||
'redirect_url' => G5_THEME_PATH.'/rb.custom/survey_form/survey_complete_page.php?sv_id=' . $sv_id . '&sr_id=' . $sr_id
|
||||
));
|
||||
exit;
|
||||
} else {
|
||||
// 완료 페이지로 이동
|
||||
goto_url(G5_THEME_PATH.'/rb.custom/survey_form/survey_complete_page.php?sv_id=' . $sv_id . '&sr_id=' . $sr_id);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
echo '<div style="padding: 20px; border: 2px solid #AA20FF; margin: 20px; background: #f9f9f9;">';
|
||||
echo '<h3>설문 폼 모듈 테스트</h3>';
|
||||
echo '<p>현재 시간: ' . date('Y-m-d H:i:s') . '</p>';
|
||||
|
||||
// 파라미터 확인
|
||||
echo '<h4>URL 파라미터:</h4>';
|
||||
echo '<ul>';
|
||||
foreach ($_GET as $key => $value) {
|
||||
echo '<li>' . htmlspecialchars($key) . ' = ' . htmlspecialchars($value) . '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
|
||||
// 라이브러리 파일 확인
|
||||
$survey_lib_path = G5_ADMIN_PATH.'/survey_manage/lib/survey.lib.php';
|
||||
echo '<h4>파일 확인:</h4>';
|
||||
echo '<p>survey.lib.php: ' . (file_exists($survey_lib_path) ? '존재함' : '없음') . '</p>';
|
||||
|
||||
// 데이터베이스 테이블 확인
|
||||
$tables = ['survey_master', 'survey_questions', 'survey_responses'];
|
||||
echo '<h4>데이터베이스 테이블:</h4>';
|
||||
echo '<ul>';
|
||||
foreach ($tables as $table) {
|
||||
$result = sql_query("SHOW TABLES LIKE '$table'", false);
|
||||
echo '<li>' . $table . ': ' . ($result && sql_num_rows($result) > 0 ? '존재함' : '없음') . '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
|
||||
// 설문 데이터 확인
|
||||
$sv_id = isset($_GET['sv_id']) ? (int)$_GET['sv_id'] : 0;
|
||||
if ($sv_id) {
|
||||
echo '<h4>설문 데이터 (sv_id: ' . $sv_id . '):</h4>';
|
||||
$survey = sql_fetch("SELECT * FROM survey_master WHERE sv_id = '$sv_id'");
|
||||
if ($survey) {
|
||||
echo '<p>제목: ' . htmlspecialchars($survey['sv_title']) . '</p>';
|
||||
echo '<p>상태: ' . $survey['sv_status'] . '</p>';
|
||||
} else {
|
||||
echo '<p>설문을 찾을 수 없습니다.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
?>
|
||||
@@ -0,0 +1,540 @@
|
||||
/* 설문 목록 모듈 스타일 */
|
||||
.survey-list-module {
|
||||
--survey-primary: #AA20FF;
|
||||
--survey-primary-light: rgba(170, 32, 255, 0.1);
|
||||
--survey-primary-dark: #8A1ACC;
|
||||
}
|
||||
|
||||
.survey-section {
|
||||
padding: 80px 0;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.survey-section .section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.survey-section .section-header .subtitle {
|
||||
color: var(--survey-primary);
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
font-size: 0.9em;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.survey-section .section-header h2 {
|
||||
font-size: 2.5em;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.survey-section .section-header p {
|
||||
font-size: 1.1em;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.survey-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 30px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.survey-card {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
transition: all 0.4s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.survey-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
.survey-card:hover {
|
||||
transform: translateY(-10px);
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.15);
|
||||
border-color: var(--survey-primary-light);
|
||||
}
|
||||
|
||||
.survey-card:hover::before {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.survey-card-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.survey-title {
|
||||
font-size: 1.4em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.3;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.survey-description {
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 20px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.survey-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.9em;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.survey-stats {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.stat-item i {
|
||||
color: var(--survey-primary);
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.survey-progress {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background: #e0e0e0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--survey-primary) 0%, var(--survey-primary-dark) 100%);
|
||||
border-radius: 4px;
|
||||
transition: width 0.6s ease;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
font-size: 0.8em;
|
||||
color: #666;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.survey-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-participate {
|
||||
flex: 1;
|
||||
padding: 12px 20px;
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-participate:hover {
|
||||
background: var(--survey-primary-dark);
|
||||
transform: translateY(-2px);
|
||||
color: white;
|
||||
box-shadow: 0 5px 15px rgba(170, 32, 255, 0.3);
|
||||
}
|
||||
|
||||
.btn-share {
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
color: #666;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-share:hover {
|
||||
background: #e9ecef;
|
||||
color: #333;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.section-footer {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.btn-more {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 15px 30px;
|
||||
background: var(--survey-primary);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 5px 15px rgba(170, 32, 255, 0.2);
|
||||
}
|
||||
|
||||
.btn-more:hover {
|
||||
background: var(--survey-primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(170, 32, 255, 0.3);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-more i {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-more:hover i {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 80px 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.empty-state i {
|
||||
font-size: 4em;
|
||||
color: #ddd;
|
||||
margin-bottom: 20px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
font-size: 1em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 모달 스타일 */
|
||||
.survey-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1050;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.survey-modal.show {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
animation: slideUp 0.4s ease-out;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 25px;
|
||||
font-size: 2rem;
|
||||
color: #aaa;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
z-index: 1;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 30px 30px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 1.5em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 0 10px 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.modal-meta {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.modal-description {
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.modal-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.modal-stats .stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.modal-stats .stat-item i {
|
||||
font-size: 1.5em;
|
||||
color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.progress-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 20px 30px 30px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
padding: 12px 24px;
|
||||
background: #f8f9fa;
|
||||
color: #666;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background: #e9ecef;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.modal-footer .btn-participate {
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.survey-section {
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.survey-section .section-header h2 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.survey-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.survey-card {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.survey-stats {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.survey-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.modal-header,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.modal-stats {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-footer .btn-participate,
|
||||
.btn-cancel {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 애니메이션 */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -40%);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.survey-card {
|
||||
animation: fadeInUp 0.6s ease forwards;
|
||||
}
|
||||
|
||||
.survey-card:nth-child(even) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.survey-card:nth-child(odd) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 호버 효과 강화 */
|
||||
.survey-card:hover .survey-title {
|
||||
color: var(--survey-primary);
|
||||
}
|
||||
|
||||
.survey-card:hover .stat-item i {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.survey-card:hover .progress-fill {
|
||||
box-shadow: 0 0 10px rgba(170, 32, 255, 0.3);
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
function initSurveyListModule(moduleId) {
|
||||
const moduleElement = document.getElementById(moduleId);
|
||||
if (!moduleElement || moduleElement.classList.contains('initialized')) return;
|
||||
|
||||
const surveySection = moduleElement.querySelector('.survey-section');
|
||||
const surveyGrid = moduleElement.querySelector('.survey-grid');
|
||||
const modal = moduleElement.querySelector('.survey-modal');
|
||||
const modalOverlay = modal.querySelector('.modal-overlay');
|
||||
const modalClose = modal.querySelector('.modal-close');
|
||||
const modalTitle = modal.querySelector('.modal-title');
|
||||
const modalAuthor = modal.querySelector('.modal-author');
|
||||
const modalDeadline = modal.querySelector('.modal-deadline');
|
||||
const modalDescription = modal.querySelector('.modal-description');
|
||||
const questionsCount = modal.querySelector('.questions-count');
|
||||
const participantsCount = modal.querySelector('.participants-count');
|
||||
const estimatedTime = modal.querySelector('.estimated-time');
|
||||
const progressFill = modal.querySelector('.progress-fill');
|
||||
const progressText = modal.querySelector('.progress-text');
|
||||
const btnParticipate = modal.querySelector('.modal-footer .btn-participate');
|
||||
const btnCancel = modal.querySelector('.btn-cancel');
|
||||
|
||||
// 설문 데이터 가져오기
|
||||
const surveysData = JSON.parse(surveySection.dataset.surveys || '[]');
|
||||
|
||||
// 설문 카드 렌더링
|
||||
function renderSurveyCards() {
|
||||
if (!surveysData.length) return;
|
||||
|
||||
const cardsHTML = surveysData.map(survey => `
|
||||
<div class="survey-card" data-survey-id="${survey.id}" style="--theme-color: ${survey.theme_color}">
|
||||
<div class="survey-card-header">
|
||||
<h3 class="survey-title">${survey.title}</h3>
|
||||
${survey.description ? `<p class="survey-description">${survey.description}</p>` : ''}
|
||||
</div>
|
||||
|
||||
<div class="survey-meta">
|
||||
<span><i class="fa fa-calendar"></i> ${survey.days_left}일 남음</span>
|
||||
<span><i class="fa fa-user"></i> ${survey.created_by}</span>
|
||||
</div>
|
||||
|
||||
<div class="survey-stats">
|
||||
<div class="stat-item">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
<span>${survey.questions_count}개 질문</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<i class="fa fa-users"></i>
|
||||
<span>${formatNumber(survey.response_count)}명 참여</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<i class="fa fa-clock"></i>
|
||||
<span>약 ${survey.questions_count}분</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${survey.max_responses ? `
|
||||
<div class="survey-progress">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style="width: ${survey.progress}%"></div>
|
||||
</div>
|
||||
<div class="progress-text">
|
||||
${formatNumber(survey.response_count)} / ${formatNumber(survey.max_responses)}명
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<div class="survey-actions">
|
||||
<button class="btn-participate" data-survey-id="${survey.id}">
|
||||
<i class="fa fa-play"></i> 참여하기
|
||||
</button>
|
||||
<button class="btn-share" data-survey-id="${survey.id}" data-title="${survey.title}">
|
||||
<i class="fa fa-share"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
surveyGrid.innerHTML = cardsHTML;
|
||||
}
|
||||
|
||||
// 모달 열기
|
||||
function openModal(surveyId) {
|
||||
const survey = surveysData.find(s => s.id == surveyId);
|
||||
if (!survey) return;
|
||||
|
||||
// 모달 내용 업데이트
|
||||
modalTitle.textContent = survey.title;
|
||||
modalAuthor.textContent = survey.created_by;
|
||||
modalDeadline.textContent = `${survey.days_left}일 남음`;
|
||||
modalDescription.textContent = survey.description || '설문에 대한 설명이 없습니다.';
|
||||
questionsCount.textContent = `${survey.questions_count}개`;
|
||||
participantsCount.textContent = `${formatNumber(survey.response_count)}명`;
|
||||
estimatedTime.textContent = `${survey.questions_count}분`;
|
||||
|
||||
// 진행률 업데이트
|
||||
if (survey.max_responses) {
|
||||
progressFill.style.width = `${survey.progress}%`;
|
||||
progressText.textContent = `${formatNumber(survey.response_count)} / ${formatNumber(survey.max_responses)}명 참여`;
|
||||
modal.querySelector('.progress-section').style.display = 'block';
|
||||
} else {
|
||||
modal.querySelector('.progress-section').style.display = 'none';
|
||||
}
|
||||
|
||||
// 참여하기 버튼 링크 설정
|
||||
btnParticipate.href = `${window.location.origin}/theme/rd.lwd/survey_page.php?sv_id=${survey.id}`;
|
||||
|
||||
// 모달 표시
|
||||
modal.classList.add('show');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
// 모달 닫기
|
||||
function closeModal() {
|
||||
modal.classList.remove('show');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// 설문 공유
|
||||
function shareSurvey(surveyId, title) {
|
||||
const url = `${window.location.origin}/theme/rd.lwd/rb.custom/survey_form/survey_page.php?sv_id=${surveyId}`;
|
||||
|
||||
if (navigator.share) {
|
||||
// Web Share API 지원시
|
||||
navigator.share({
|
||||
title: title,
|
||||
text: '설문에 참여해보세요!',
|
||||
url: url
|
||||
}).catch(err => {
|
||||
console.log('공유 취소:', err);
|
||||
});
|
||||
} else {
|
||||
// 클립보드에 복사
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
showNotification('설문 링크가 클립보드에 복사되었습니다!', 'success');
|
||||
}).catch(() => {
|
||||
// 클립보드 복사 실패시 프롬프트로 표시
|
||||
prompt('설문 링크를 복사하세요:', url);
|
||||
});
|
||||
} else {
|
||||
// 클립보드 API 미지원시 프롬프트로 표시
|
||||
prompt('설문 링크를 복사하세요:', url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 알림 표시
|
||||
function showNotification(message, type = 'info') {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `survey-notification survey-notification-${type}`;
|
||||
notification.innerHTML = `
|
||||
<div class="notification-content">
|
||||
<i class="fa fa-${type === 'success' ? 'check-circle' : 'info-circle'}"></i>
|
||||
<span>${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 스타일 추가
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: ${type === 'success' ? '#28a745' : '#17a2b8'};
|
||||
color: white;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
z-index: 1060;
|
||||
animation: slideInRight 0.3s ease;
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.animation = 'slideOutRight 0.3s ease';
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 숫자 포맷팅
|
||||
function formatNumber(num) {
|
||||
return new Intl.NumberFormat('ko-KR').format(num);
|
||||
}
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
function bindEvents() {
|
||||
// 설문 카드 클릭 (모달 열기)
|
||||
surveyGrid.addEventListener('click', (e) => {
|
||||
const card = e.target.closest('.survey-card');
|
||||
if (card && !e.target.closest('.survey-actions')) {
|
||||
const surveyId = card.dataset.surveyId;
|
||||
openModal(surveyId);
|
||||
}
|
||||
});
|
||||
|
||||
// 참여하기 버튼 클릭
|
||||
surveyGrid.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.btn-participate')) {
|
||||
e.stopPropagation();
|
||||
const surveyId = e.target.closest('.btn-participate').dataset.surveyId;
|
||||
window.location.href = `${window.location.origin}/theme/rd.lwd/rb.custom/survey_form/survey_page.php?sv_id=${surveyId}`;
|
||||
}
|
||||
});
|
||||
|
||||
// 공유 버튼 클릭
|
||||
surveyGrid.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.btn-share')) {
|
||||
e.stopPropagation();
|
||||
const shareBtn = e.target.closest('.btn-share');
|
||||
const surveyId = shareBtn.dataset.surveyId;
|
||||
const title = shareBtn.dataset.title;
|
||||
shareSurvey(surveyId, title);
|
||||
}
|
||||
});
|
||||
|
||||
// 모달 닫기 이벤트
|
||||
modalClose.addEventListener('click', closeModal);
|
||||
btnCancel.addEventListener('click', closeModal);
|
||||
modalOverlay.addEventListener('click', closeModal);
|
||||
|
||||
// ESC 키로 모달 닫기
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && modal.classList.contains('show')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// 카드 호버 효과
|
||||
surveyGrid.addEventListener('mouseenter', (e) => {
|
||||
const card = e.target.closest('.survey-card');
|
||||
if (card) {
|
||||
const themeColor = card.style.getPropertyValue('--theme-color') || '#AA20FF';
|
||||
card.style.setProperty('--survey-primary', themeColor);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
// 스크롤 애니메이션
|
||||
function initScrollAnimation() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.animationPlayState = 'running';
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
});
|
||||
|
||||
// 카드들에 애니메이션 적용
|
||||
setTimeout(() => {
|
||||
const cards = surveyGrid.querySelectorAll('.survey-card');
|
||||
cards.forEach((card, index) => {
|
||||
card.style.animationDelay = `${index * 0.1}s`;
|
||||
card.style.animationPlayState = 'paused';
|
||||
observer.observe(card);
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 진행률 바 애니메이션
|
||||
function animateProgressBars() {
|
||||
const progressBars = surveyGrid.querySelectorAll('.progress-fill');
|
||||
progressBars.forEach(bar => {
|
||||
const width = bar.style.width;
|
||||
bar.style.width = '0%';
|
||||
setTimeout(() => {
|
||||
bar.style.width = width;
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
// 초기화
|
||||
function init() {
|
||||
renderSurveyCards();
|
||||
bindEvents();
|
||||
initScrollAnimation();
|
||||
|
||||
// 진행률 바 애니메이션 (약간의 지연 후)
|
||||
setTimeout(animateProgressBars, 800);
|
||||
|
||||
moduleElement.classList.add('initialized');
|
||||
}
|
||||
|
||||
// 모듈 초기화 실행
|
||||
init();
|
||||
}
|
||||
|
||||
// 추가 CSS 애니메이션 (JavaScript로 동적 추가)
|
||||
const additionalStyles = `
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutRight {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.survey-notification .notification-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.survey-notification i {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
`;
|
||||
|
||||
// 스타일 추가 (한 번만)
|
||||
if (!document.getElementById('survey-list-module-styles')) {
|
||||
const styleSheet = document.createElement('style');
|
||||
styleSheet.id = 'survey-list-module-styles';
|
||||
styleSheet.textContent = additionalStyles;
|
||||
document.head.appendChild(styleSheet);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// 설문 관리 라이브러리 로드
|
||||
include_once(G5_ADMIN_PATH.'/survey_manage/lib/survey.lib.php');
|
||||
|
||||
// 설문 데이터 가져오기
|
||||
$limit = 6; // 표시할 설문 수
|
||||
$where = " WHERE sv_status = 'active' ";
|
||||
$where .= " AND DATE(sv_start_date) <= CURDATE() ";
|
||||
$where .= " AND DATE(sv_end_date) >= CURDATE() ";
|
||||
|
||||
$sql = " SELECT * FROM survey_master $where ORDER BY sv_created_at DESC LIMIT $limit ";
|
||||
$result = sql_query($sql);
|
||||
|
||||
$survey_data = array();
|
||||
while ($row = sql_fetch_array($result)) {
|
||||
$questions_count = sql_fetch("SELECT COUNT(*) as cnt FROM survey_questions WHERE sv_id = '{$row['sv_id']}'")['cnt'];
|
||||
$response_count = get_survey_response_count($row['sv_id'], 'completed');
|
||||
$max_responses = $row['sv_max_responses'];
|
||||
$progress = $max_responses ? ($response_count / $max_responses) * 100 : 0;
|
||||
$days_left = ceil((strtotime($row['sv_end_date']) - time()) / (60 * 60 * 24));
|
||||
|
||||
$survey_data[] = array(
|
||||
'id' => $row['sv_id'],
|
||||
'title' => get_text($row['sv_title']),
|
||||
'description' => get_text(cut_str(strip_tags($row['sv_description']), 100)),
|
||||
'questions_count' => $questions_count,
|
||||
'response_count' => $response_count,
|
||||
'max_responses' => $max_responses,
|
||||
'progress' => min($progress, 100),
|
||||
'days_left' => $days_left,
|
||||
'theme_color' => $row['sv_theme_color'] ?: '#AA20FF',
|
||||
'created_by' => $row['sv_created_by']
|
||||
);
|
||||
}
|
||||
|
||||
$survey_json = json_encode($survey_data, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// CSS와 JS 파일의 버전을 파일 수정 시간으로 자동 갱신
|
||||
$module_css_path = G5_THEME_PATH.'/rb.custom/survey_list/module.css';
|
||||
$module_js_path = G5_THEME_PATH.'/rb.custom/survey_list/module.js';
|
||||
$module_css_ver = file_exists($module_css_path) ? filemtime($module_css_path) : G5_CSS_VER;
|
||||
$module_js_ver = file_exists($module_js_path) ? filemtime($module_js_path) : G5_JS_VER;
|
||||
|
||||
// 이 모듈만의 고유 ID를 생성합니다.
|
||||
$module_id = 'survey_list_module_'.uniqid();
|
||||
?>
|
||||
|
||||
<!-- 모듈의 가장 바깥 요소에 고유 ID를 부여합니다. -->
|
||||
<div id="<?php echo $module_id; ?>" class="survey-list-module">
|
||||
<section class="survey-section" data-surveys='<?php echo htmlspecialchars($survey_json, ENT_QUOTES, 'UTF-8'); ?>'>
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<span class="subtitle">Survey</span>
|
||||
<h2>설문조사</h2>
|
||||
<p>다양한 설문에 참여하고 소중한 의견을 나눠주세요</p>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($survey_data)): ?>
|
||||
<div class="survey-grid">
|
||||
<!-- JS로 설문 카드가 생성될 영역 -->
|
||||
</div>
|
||||
|
||||
<div class="section-footer">
|
||||
<a href="<?php echo G5_THEME_URL; ?>/rb.custom/survey_list/survey_list_page.php" class="btn-more">
|
||||
<span>모든 설문 보기</span>
|
||||
<i class="fa fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="empty-state">
|
||||
<i class="fa fa-poll"></i>
|
||||
<h3>진행중인 설문이 없습니다</h3>
|
||||
<p>새로운 설문이 등록되면 알려드리겠습니다.</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 설문 상세 모달 -->
|
||||
<div class="survey-modal">
|
||||
<div class="modal-overlay"></div>
|
||||
<div class="modal-content">
|
||||
<button type="button" class="modal-close">×</button>
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"></h3>
|
||||
<div class="modal-meta">
|
||||
<span class="modal-author"></span>
|
||||
<span class="modal-deadline"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="modal-description"></p>
|
||||
<div class="modal-stats">
|
||||
<div class="stat-item">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
<span class="stat-label">질문 수</span>
|
||||
<span class="stat-value questions-count"></span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<i class="fa fa-users"></i>
|
||||
<span class="stat-label">참여자</span>
|
||||
<span class="stat-value participants-count"></span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<i class="fa fa-clock"></i>
|
||||
<span class="stat-label">예상 시간</span>
|
||||
<span class="stat-value estimated-time"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress-section">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill"></div>
|
||||
</div>
|
||||
<div class="progress-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn-cancel">취소</button>
|
||||
<a href="#" class="btn-participate">참여하기</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 모듈에 필요한 CSS 파일을 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/survey_list/module.css?ver=<?php echo $module_css_ver; ?>">
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const currentModuleId = '<?php echo $module_id; ?>';
|
||||
const initFunctionName = 'initSurveyListModule';
|
||||
const scriptId = 'survey-list-module-script';
|
||||
|
||||
if (document.getElementById(scriptId)) {
|
||||
if (typeof window[initFunctionName] === 'function') {
|
||||
window[initFunctionName](currentModuleId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.src = '<?php echo G5_THEME_URL; ?>/rb.custom/survey_list/module.js?ver=<?php echo $module_js_ver; ?>';
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
if (typeof window[initFunctionName] === 'function') {
|
||||
window[initFunctionName](currentModuleId);
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
include_once('../../../../common.php');
|
||||
|
||||
$g5['title'] = '설문조사';
|
||||
include_once(G5_THEME_PATH.'/head.sub.php');
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* 페이지 전용 스타일 */
|
||||
body {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
padding-top: 100px; /* 헤더 높이만큼 */
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background: linear-gradient(135deg, #AA20FF 0%, #8A1ACC 100%);
|
||||
color: white;
|
||||
padding: 80px 0;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
font-size: 3em;
|
||||
font-weight: 700;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.page-header p {
|
||||
font-size: 1.2em;
|
||||
opacity: 0.9;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
background: white;
|
||||
padding: 40px 0;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
padding: 15px 20px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 50px;
|
||||
font-size: 1em;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
outline: none;
|
||||
border-color: #AA20FF;
|
||||
box-shadow: 0 0 0 3px rgba(170, 32, 255, 0.1);
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
padding: 15px 30px;
|
||||
background: #AA20FF;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.search-btn:hover {
|
||||
background: #8A1ACC;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(170, 32, 255, 0.3);
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
padding: 10px 20px;
|
||||
background: white;
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
border-radius: 25px;
|
||||
border: 2px solid #e0e0e0;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.filter-tab:hover,
|
||||
.filter-tab.active {
|
||||
background: #AA20FF;
|
||||
color: white;
|
||||
border-color: #AA20FF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.surveys-section {
|
||||
padding: 0 0 80px 0;
|
||||
}
|
||||
|
||||
/* 반응형 */
|
||||
@media (max-width: 768px) {
|
||||
.page-container {
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
font-size: 2.2em;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
flex-direction: column;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="page-container">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<h1><i class="fa fa-poll"></i> 설문조사</h1>
|
||||
<p>다양한 설문에 참여하고 소중한 의견을 나눠주세요</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 검색 섹션 -->
|
||||
<div class="search-section">
|
||||
<div class="container">
|
||||
<form method="get" class="search-form">
|
||||
<input type="text"
|
||||
name="stx"
|
||||
value="<?php echo htmlspecialchars($_GET['stx'] ?? ''); ?>"
|
||||
placeholder="관심있는 설문을 검색해보세요..."
|
||||
class="search-input">
|
||||
<button type="submit" class="search-btn">
|
||||
<i class="fa fa-search"></i> 검색
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 필터 섹션 -->
|
||||
<div class="filter-section">
|
||||
<div class="container">
|
||||
<div class="filter-tabs">
|
||||
<a href="?" class="filter-tab <?php echo !isset($_GET['category']) ? 'active' : ''; ?>">전체</a>
|
||||
<a href="?category=customer" class="filter-tab <?php echo ($_GET['category'] ?? '') == 'customer' ? 'active' : ''; ?>">고객서비스</a>
|
||||
<a href="?category=product" class="filter-tab <?php echo ($_GET['category'] ?? '') == 'product' ? 'active' : ''; ?>">제품개발</a>
|
||||
<a href="?category=marketing" class="filter-tab <?php echo ($_GET['category'] ?? '') == 'marketing' ? 'active' : ''; ?>">마케팅</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 설문 목록 섹션 (rb.custom 모듈 사용) -->
|
||||
<div class="surveys-section">
|
||||
<?php
|
||||
// 전체 설문 목록을 위한 커스텀 모듈 (확장된 버전)
|
||||
include_once(G5_THEME_PATH.'/rb.custom/survey_list/module.php');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once(G5_THEME_PATH.'/tail.sub.php');
|
||||
?>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
/**
|
||||
* 게시판 최신글 또는 콘텐츠 페이지를 탭으로 생성하는 함수
|
||||
*
|
||||
* @param array $tabs_config 탭 설정 배열
|
||||
* @return string 생성된 탭 HTML
|
||||
*/
|
||||
function rb_tabs($tabs_config) {
|
||||
// 💡 [복원] 설정값이 유효한지 확인하는 필수 코드
|
||||
if (!is_array($tabs_config) || empty($tabs_config)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 💡 [복원] 고유 ID 생성 (한 페이지에 여러 탭 모듈이 있어도 충돌 방지)
|
||||
$module_id = 'rb-tab-module-' . uniqid();
|
||||
|
||||
// 💡 [복원] 이 모듈에 필요한 CSS와 JS를 동적으로 추가합니다.
|
||||
add_stylesheet('<link rel="stylesheet" href="'.G5_THEME_URL.'/rb.custom/tabs/tab_style.css?ver='.G5_SERVER_TIME.'">', 0);
|
||||
add_javascript('<script src="'.G5_THEME_URL.'/rb.custom/tabs/tab_script.js?ver='.G5_SERVER_TIME.'"></script>', 10);
|
||||
|
||||
// 💡 [복원] HTML 출력을 안전하게 버퍼에 담기 시작
|
||||
ob_start();
|
||||
?>
|
||||
<div class="rb-tab-module" id="<?php echo $module_id; ?>">
|
||||
<!-- 1. 탭 네비게이션 -->
|
||||
<ul class="rb-tab-nav">
|
||||
<?php foreach ($tabs_config as $index => $tab): ?>
|
||||
<?php
|
||||
$tab_id = $tab['type'] . '-' . $tab['id'];
|
||||
$is_active = ($index === 0) ? 'active' : '';
|
||||
?>
|
||||
<li><a href="#<?php echo $tab_id; ?>" class="<?php echo $is_active; ?>"><?php echo htmlspecialchars($tab['title']); ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<!-- 2. 탭 콘텐츠 -->
|
||||
<div class="rb-tab-content-wrapper">
|
||||
<?php foreach ($tabs_config as $index => $tab): ?>
|
||||
<?php
|
||||
$tab_id = $tab['type'] . '-' . $tab['id'];
|
||||
$is_active = ($index === 0) ? 'active' : '';
|
||||
?>
|
||||
<div id="<?php echo $tab_id; ?>" class="rb-tab-content <?php echo $is_active; ?>">
|
||||
<?php
|
||||
// 💡 [핵심] 탭 타입에 따라 다른 내용을 불러옵니다.
|
||||
switch ($tab['type']) {
|
||||
case 'board':
|
||||
// 💡 [개선] 타입이 'board'이면 탭 전용 최신글 스킨(rb_tab_basic)을 불러옵니다.
|
||||
$options = $tab['options'] ?? [];
|
||||
$rows = $options['rows'] ?? 5;
|
||||
$subject_len = $options['subject_len'] ?? 40;
|
||||
echo latest('rb_tab_basic', $tab['id'], $rows, $subject_len);
|
||||
break;
|
||||
|
||||
case 'content':
|
||||
// 타입이 'content'이면 g5_content 테이블에서 내용을 불러옵니다.
|
||||
$co = get_content_db($tab['id']);
|
||||
if ($co) {
|
||||
echo conv_content($co['co_content'], $co['co_html']);
|
||||
} else {
|
||||
echo '<div class="no-posts">콘텐츠('.htmlspecialchars($tab['id']).')를 찾을 수 없습니다.</div>';
|
||||
}
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
// 💡 [복원] 버퍼에 담긴 HTML을 반환하고 버퍼를 비웁니다.
|
||||
return ob_get_clean();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tabModules = document.querySelectorAll('.rb-tab-module');
|
||||
|
||||
tabModules.forEach(module => {
|
||||
const navLinks = module.querySelectorAll('.rb-tab-nav a');
|
||||
const contentPanes = module.querySelectorAll('.rb-tab-content');
|
||||
|
||||
navLinks.forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
navLinks.forEach(item => item.classList.remove('active'));
|
||||
contentPanes.forEach(pane => pane.classList.remove('active'));
|
||||
|
||||
this.classList.add('active');
|
||||
const targetId = this.getAttribute('href');
|
||||
const targetPane = module.querySelector(targetId);
|
||||
if (targetPane) {
|
||||
targetPane.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
/* 탭 모듈 전체 */
|
||||
.rb-tab-module {
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 탭 네비게이션 */
|
||||
.rb-tab-nav {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.rb-tab-nav a {
|
||||
display: block;
|
||||
padding: 12px 20px;
|
||||
text-decoration: none;
|
||||
color: #555;
|
||||
font-weight: 500;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.rb-tab-nav a.active {
|
||||
color: #0056b3;
|
||||
font-weight: 700;
|
||||
border-bottom-color: #0056b3;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 탭 콘텐츠 */
|
||||
.rb-tab-content-wrapper {
|
||||
padding: 15px;
|
||||
position: relative;
|
||||
}
|
||||
.rb-tab-content {
|
||||
display: none;
|
||||
}
|
||||
.rb-tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
.rb-tab-content .no-posts {
|
||||
color: #999;
|
||||
padding: 30px 0;
|
||||
text-align: center;
|
||||
}
|
||||
/* latest 스킨(basic)을 탭 내부에 맞게 스타일 조정 */
|
||||
.rb-tab-content .lat {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
.rb-tab-content .lat ul {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* ==========================================================================
|
||||
* 💡 tech_section 모듈 전용 스타일시트
|
||||
* ==========================================================================
|
||||
*/
|
||||
|
||||
/* --- 1. 섹션 기본 스타일 --- */
|
||||
.products-trend-section {
|
||||
width: 100%;
|
||||
padding: 80px 0;
|
||||
background-color: #ffffff; /* 또는 원하는 배경색 */
|
||||
}
|
||||
|
||||
/* --- 2. 섹션 헤더 (제목, 부제) --- */
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.section-header .subtitle {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #0056b3; /* 포인트 색상 */
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 36px;
|
||||
font-weight: 900;
|
||||
color: #25282B; /* 기본 텍스트 색상 */
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.section-header p {
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* --- 3. 제품 카드 그리드 --- */
|
||||
.product-grid {
|
||||
display: grid;
|
||||
/* 💡 화면 크기에 따라 1~3개의 컬럼으로 자동 조정됩니다. */
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
/* --- 4. 개별 제품 카드 --- */
|
||||
.product-card-trend {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.product-card-trend:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* --- 5. 카드 내부 요소 --- */
|
||||
.product-image-trend {
|
||||
width: 100%;
|
||||
/* 💡 이미지 비율을 4:3으로 유지합니다. */
|
||||
aspect-ratio: 4 / 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-image-trend.is-patent {
|
||||
padding: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.product-image-trend img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; /* 이미지가 잘리지 않고 꽉 차도록 설정 */
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
.product-card-trend:hover .product-image-trend img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.product-info-trend {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.product-info-trend h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.product-info-trend p {
|
||||
font-size: 0.95rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* --- 9. 스크롤 애니메이션 (style_prestige_1.css에서 가져옴) --- */
|
||||
.reveal-up, .reveal-fade {
|
||||
opacity: 0;
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
}
|
||||
.reveal-up { transform: translateY(40px); }
|
||||
.reveal-fade { transform: scale(0.95); }
|
||||
.reveal-up.is-revealed, .reveal-fade.is-revealed {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
/* --- 10. [모듈 전용] 이미지 팝업 모달 스타일 (개선) --- */
|
||||
.image-modal {
|
||||
display: none; /* 기본적으로 숨김 */
|
||||
position: fixed;
|
||||
z-index: 1050;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto; /* 내용이 클 경우 스크롤 */
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px 20px; /* 화면 가장자리와 여백 */
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.image-modal.is-active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
width: auto; /* 너비를 자동으로 설정 */
|
||||
max-width: 100%; /* 화면 너비를 넘지 않도록 설정 */
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,.5);
|
||||
animation: modal-slide-down 0.4s ease-out;
|
||||
display: flex; /* 내부 요소 정렬을 위해 flex 사용 */
|
||||
flex-direction: column; /* 이미지와 텍스트를 세로로 쌓음 */
|
||||
}
|
||||
|
||||
@keyframes modal-slide-down {
|
||||
from {
|
||||
transform: translateY(-50px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content .modal-image {
|
||||
display: block;
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
object-fit: contain;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.modal-info {
|
||||
padding: 20px 25px;
|
||||
max-width: 800px; /* 텍스트 영역의 최대 너비는 제한 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-info .modal-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.modal-info .modal-desc {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 25px;
|
||||
font-size: 35px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.5);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.close-btn:hover,
|
||||
.close-btn:focus {
|
||||
color: #ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
/* --- 11. [개선] 가독성 향상을 위한 줄바꿈 처리 --- */
|
||||
.section-header h2,
|
||||
.section-header p,
|
||||
.product-info-trend h3,
|
||||
.product-info-trend p,
|
||||
.item-info h3,
|
||||
.item-info p {
|
||||
word-break: keep-all;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
/* --- 12. [개선] 카드 설명 텍스트 잘림 방지 및 높이 고정 --- */
|
||||
.product-info-trend p,
|
||||
.item-info p {
|
||||
height: 3.04rem;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.6;
|
||||
}
|
||||
/* -------------------------------------------------- */
|
||||
/* 💡 [최종 수정] 모달 스크롤바 완전 숨김 처리 */
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
/* 1. 기본 상태: 스크롤바를 완전히 투명하게 만듭니다. */
|
||||
.rb-modal-overlay,
|
||||
.rb-modal-body {
|
||||
/* Firefox: 스크롤바 색상을 양쪽 모두 투명하게 설정 */
|
||||
scrollbar-color: transparent transparent;
|
||||
scrollbar-width: thin;
|
||||
transition: scrollbar-color 0.3s ease; /* 부드러운 효과를 위해 추가 */
|
||||
}
|
||||
|
||||
.rb-modal-overlay::-webkit-scrollbar,
|
||||
.rb-modal-body::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.rb-modal-overlay::-webkit-scrollbar-track,
|
||||
.rb-modal-body::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.rb-modal-overlay::-webkit-scrollbar-thumb,
|
||||
.rb-modal-body::-webkit-scrollbar-thumb {
|
||||
/* Webkit: 스크롤바 막대를 투명하게 */
|
||||
background-color: transparent;
|
||||
border-radius: 10px;
|
||||
border: 3px solid transparent;
|
||||
background-clip: padding-box;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* 2. :hover 상태: 마우스를 올리면 스크롤바가 나타납니다. */
|
||||
.rb-modal-overlay:hover,
|
||||
.rb-modal-body:hover {
|
||||
/* Firefox: 스크롤바 색상을 보이게 변경 */
|
||||
scrollbar-color: rgba(0, 0, 0, 0.4) transparent;
|
||||
}
|
||||
|
||||
.rb-modal-overlay:hover::-webkit-scrollbar-thumb,
|
||||
.rb-modal-body:hover::-webkit-scrollbar-thumb {
|
||||
/* Webkit: 스크롤바 막대 색상을 보이게 변경 */
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// 💡 [핵심 수정] 모든 로직을 초기화 함수 안으로 옮기고, 모듈의 고유 ID를 인자로 받도록 변경합니다.
|
||||
function initTechSectionModule(moduleId) {
|
||||
// 💡 [핵심 수정] document가 아닌, 전달받은 moduleId를 기준으로 요소를 찾습니다.
|
||||
const moduleElement = document.getElementById(moduleId);
|
||||
if (!moduleElement) return;
|
||||
|
||||
// 이미 초기화된 모듈은 다시 실행하지 않습니다.
|
||||
if (moduleElement.classList.contains('initialized')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const section = moduleElement.querySelector('.products-trend-section');
|
||||
const patentGrid = moduleElement.querySelector('.product-grid');
|
||||
const modal = moduleElement.querySelector('.image-modal');
|
||||
|
||||
if (!section || !patentGrid || !modal) {
|
||||
console.error('Module elements not found in:', moduleId);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 그리드에 특허 카드를 렌더링하는 함수
|
||||
*/
|
||||
function renderGrid() {
|
||||
const patentsJson = section.dataset.patents;
|
||||
let patentsData;
|
||||
|
||||
try {
|
||||
patentsData = JSON.parse(patentsJson);
|
||||
} catch (e) {
|
||||
patentGrid.innerHTML = '<p style="text-align:center; padding: 40px 0; color: #d9534f;">기술 자료를 불러오는 데 실패했습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!patentsData || patentsData.length === 0) {
|
||||
patentGrid.innerHTML = '<p style="text-align:center; padding: 40px 0; color: #888;">표시할 기술 자료가 없습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const patentCardsHTML = patentsData.map(item => `
|
||||
<div class="product-card-trend js-modal-trigger" data-title="${item.title}" data-desc="${item.description}" data-img="${item.image}">
|
||||
<div class="product-image-trend is-patent">
|
||||
<img src="${item.image}" alt="${item.title}">
|
||||
</div>
|
||||
<div class="product-info-trend">
|
||||
<h3>${item.title}</h3>
|
||||
<p>${item.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
patentGrid.innerHTML = patentCardsHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* 모달 관련 이벤트를 설정하는 함수
|
||||
*/
|
||||
function setupModalEvents() {
|
||||
const modalImage = modal.querySelector('.modal-image');
|
||||
const modalTitle = modal.querySelector('.modal-title');
|
||||
const modalDesc = modal.querySelector('.modal-desc');
|
||||
const closeBtn = modal.querySelector('.close-btn');
|
||||
|
||||
// 모달 열기 (이벤트 위임)
|
||||
patentGrid.addEventListener('click', function(event) {
|
||||
const card = event.target.closest('.js-modal-trigger');
|
||||
if (card) {
|
||||
modalImage.src = card.dataset.img;
|
||||
modalTitle.textContent = card.dataset.title;
|
||||
modalDesc.textContent = card.dataset.desc;
|
||||
modal.classList.add('is-active');
|
||||
}
|
||||
});
|
||||
|
||||
// 모달 닫기 함수
|
||||
function closeModal() {
|
||||
modal.classList.remove('is-active');
|
||||
}
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
modal.addEventListener('click', function(event) {
|
||||
if (event.target === modal) closeModal();
|
||||
});
|
||||
// ESC 키 이벤트는 document에 등록해야 하므로, 모달이 활성화 상태일 때만 동작하도록 조건 추가
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape' && modal.classList.contains('is-active')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 함수 실행
|
||||
renderGrid();
|
||||
setupModalEvents();
|
||||
|
||||
// 초기화 완료 클래스 추가
|
||||
moduleElement.classList.add('initialized');
|
||||
}
|
||||
|
||||
// 💡 [핵심 수정] 다른 곳에서 이 함수를 다시 호출할 수 있도록 전역에 노출시킵니다.
|
||||
window.initTechSectionModule = initTechSectionModule;
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
|
||||
// --- 데이터 처리 ---
|
||||
$patents_data = array();
|
||||
$sql = " SELECT wr_id, wr_subject, wr_content FROM {$g5['write_prefix']}patents WHERE wr_is_comment = 0 ORDER BY wr_num, wr_reply LIMIT 3 ";
|
||||
$result = sql_query($sql);
|
||||
for ($i=0; $row=sql_fetch_array($result); $i++) {
|
||||
$file = get_file('patents', $row['wr_id']);
|
||||
$image_url = (isset($file[0]['path']) && isset($file[0]['file'])) ? $file[0]['path'].'/'.$file[0]['file'] : G5_THEME_URL.'/img/no_image.png';
|
||||
|
||||
$patents_data[] = array(
|
||||
'id' => $row['wr_id'],
|
||||
'title' => get_text($row['wr_subject']),
|
||||
'description' => get_text(cut_str(strip_tags($row['wr_content']), 100)),
|
||||
'image' => $image_url
|
||||
);
|
||||
}
|
||||
$patents_json = json_encode($patents_data, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// 💡 [개선] CSS와 JS 파일의 버전을 파일 수정 시간으로 자동 갱신하여 캐시 관리를 최적화합니다.
|
||||
$module_css_path = G5_THEME_PATH.'/rb.custom/tech_section/module.css';
|
||||
$module_js_path = G5_THEME_PATH.'/rb.custom/tech_section/module.js';
|
||||
$module_css_ver = file_exists($module_css_path) ? filemtime($module_css_path) : G5_CSS_VER;
|
||||
$module_js_ver = file_exists($module_js_path) ? filemtime($module_js_path) : G5_JS_VER;
|
||||
|
||||
// 💡 [핵심] 이 모듈만의 고유 ID를 생성합니다.
|
||||
$module_id = 'tech_section_'.uniqid();
|
||||
?>
|
||||
|
||||
<!-- 💡 [핵심 수정] 모듈의 가장 바깥 요소에 고유 ID를 부여합니다. -->
|
||||
<div id="<?php echo $module_id; ?>" class="tech-section-module">
|
||||
<!-- TECH: 기술력 및 특허 섹션 -->
|
||||
<section class="products-trend-section" data-patents='<?php echo htmlspecialchars($patents_json, ENT_QUOTES, 'UTF-8'); ?>'>
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<span class="subtitle">Technology</span>
|
||||
<h2>문 하나에 사람을 담았습니다.</h2>
|
||||
<p>당신의 공간이 더욱 안전하고 조용해지도록, 우리는 문 하나를 넘어서고 있습니다.</p>
|
||||
</div>
|
||||
<div class="product-grid">
|
||||
<!-- JS로 특허증 카드 생성 -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 💡 [핵심 수정] 모듈 내부에 모달 HTML을 포함시킵니다. -->
|
||||
<div class="image-modal">
|
||||
<div class="modal-content">
|
||||
<span class="close-btn">×</span>
|
||||
<img class="modal-image" src="" alt="제품 이미지">
|
||||
<div class="modal-info">
|
||||
<h3 class="modal-title"></h3>
|
||||
<p class="modal-desc"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이 모듈에 필요한 CSS 파일을 불러옵니다. -->
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/tech_section/module.css?ver=<?php echo $module_css_ver; ?>">
|
||||
|
||||
<?php // 💡 [핵심 수정] AJAX로 로드될 때도 스크립트가 확실하게 실행되도록 동적 로딩 방식으로 변경합니다. ?>
|
||||
<script>
|
||||
(function() {
|
||||
// 💡 [핵심 수정] 이 모듈의 고유 ID를 자바스크립트로 전달합니다.
|
||||
const currentModuleId = '<?php echo $module_id; ?>';
|
||||
const scriptId = 'tech-section-module-script';
|
||||
|
||||
// 스크립트가 이미 로드되었는지 확인 (중복 실행 방지)
|
||||
if (document.getElementById(scriptId)) {
|
||||
// 이미 로드되었다면, 초기화 함수만 다시 호출
|
||||
if (typeof window.initTechSectionModule === 'function') {
|
||||
window.initTechSectionModule(currentModuleId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.src = '<?php echo G5_THEME_URL; ?>/rb.custom/tech_section/module.js?ver=<?php echo $module_js_ver; ?>';
|
||||
script.async = true;
|
||||
|
||||
// 💡 [핵심 수정] 스크립트 로드가 완료되면, 고유 ID를 인자로 전달하여 초기화 함수를 호출합니다.
|
||||
script.onload = () => {
|
||||
if (typeof window.initTechSectionModule === 'function') {
|
||||
window.initTechSectionModule(currentModuleId);
|
||||
}
|
||||
};
|
||||
|
||||
script.onerror = () => {
|
||||
console.error('Failed to load tech_section/module.js');
|
||||
};
|
||||
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user