Files
sam-sales/index.php
aweso 7fd66f681a 문어 컬렉션 추가
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-07 16:41:07 +09:00

1058 lines
64 KiB
PHP

<?php require_once 'session.php'; ?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>영업 관리 시스템</title>
<!-- Favicon -->
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
<link rel="shortcut icon" href="img/favicon.png">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+KR:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'Noto Sans KR', 'sans-serif'],
},
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
900: '#0c4a6e',
}
},
animation: {
blob: "blob 7s infinite",
'fade-in-up': 'fadeInUp 0.8s ease-out forwards',
},
keyframes: {
blob: {
"0%": { transform: "translate(0px, 0px) scale(1)" },
"33%": { transform: "translate(30px, -50px) scale(1.1)" },
"66%": { transform: "translate(-20px, 20px) scale(0.9)" },
"100%": { transform: "translate(0px, 0px) scale(1)" },
},
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
}
},
}
}
}
</script>
<style>
.delay-100 { animation-delay: 100ms; }
.delay-200 { animation-delay: 200ms; }
.delay-300 { animation-delay: 300ms; }
.animation-delay-2000 { animation-delay: 2s; }
.animation-delay-4000 { animation-delay: 4s; }
/* Hide scrollbar for clean modal */
.no-scroll { overflow: hidden; }
/* Image Zoom & Float Effect */
.img-zoom-container {
overflow: visible !important;
perspective: 1000px;
}
.img-zoom-target {
cursor: zoom-in;
transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
position: relative;
z-index: 1;
/* 인라인 스타일을 클래스로 통합 */
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
transform: translateZ(0);
backface-visibility: hidden;
}
.img-zoom-target:hover {
transform: scale(1.1) translateZ(0) !important;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
z-index: 50;
}
/* Full Size Viewer */
.img-full-container {
max-height: 70vh;
overflow: auto;
cursor: grab;
background: #f8fafc;
border-radius: 0.75rem;
border: 1px solid #e2e8f0;
}
.img-full-container:active { cursor: grabbing; }
.img-natural {
max-width: none !important;
width: auto !important;
height: auto !important;
}
/* Full Screen Lightbox */
#fullscreen-view {
position: fixed;
inset: 0;
background: rgba(15, 23, 42, 0.95);
z-index: 100;
overflow-y: auto;
display: none;
flex-direction: column;
align-items: center;
padding: 2rem 0; /* 상하 여백 */
}
#fullscreen-view img {
width: 100%; /* 기기 너비 꽉 채움 */
max-width: 1400px; /* PC에서는 너무 커지지 않게 제한 (선택 가능) */
height: auto;
display: block;
box-shadow: 0 0 50px rgba(0,0,0,0.5);
}
.fullscreen-close {
position: fixed;
top: 1.5rem;
right: 1.5rem;
z-index: 110;
background: white;
border-radius: 9999px;
padding: 0.75rem;
cursor: pointer;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}
/* Mobile touch optimization */
.touch-manipulation {
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
/* Mobile title optimization - prevent single character line breaks */
@media (max-width: 640px) {
.break-keep {
word-break: keep-all;
overflow-wrap: break-word;
hyphens: none;
}
/* 타이틀 폰트 크기 조정으로 한 글자 줄바꿈 방지 */
h1, h2, h3.title-responsive {
font-size: clamp(1rem, 4vw, 1.5rem);
line-height: 1.3;
}
/* 모바일 버튼 텍스트 줄바꿈 방지 */
button {
word-break: keep-all;
white-space: nowrap;
}
}
</style>
</head>
<body class="bg-slate-50 text-slate-900 font-sans selection:bg-brand-200 selection:text-brand-900">
<!-- Toast Notification -->
<div id="toast" class="fixed top-24 right-4 z-[60] bg-slate-800 text-white px-6 py-4 rounded-xl shadow-2xl flex items-center gap-3 transition-all duration-500 transform translate-x-full opacity-0">
<i data-lucide="check-circle-2" class="text-green-400 w-6 h-6"></i>
<div>
<h4 class="font-bold text-sm">다운로드 시작됨</h4>
<p class="text-slate-400 text-xs">CodeBridgeX_Proposal_v2.4.pdf</p>
</div>
</div>
<!-- Navigation -->
<nav class="sticky top-0 z-30 bg-white/80 backdrop-blur-md border-b border-slate-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<div class="flex items-center gap-3 cursor-pointer" onclick="filterAssets('All')">
<div class="w-8 h-8 bg-brand-600 rounded-lg flex items-center justify-center text-white font-bold text-lg shadow-lg shadow-brand-200">
S
</div>
<span class="text-xl font-bold tracking-tight text-slate-900">CodeBridgeX <span class="text-brand-600">SAM</span></span>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center gap-4">
<!-- <a href="sales_scenario/" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors">영업 시나리오</a>
<a href="sales_manager_scenario/" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors">매니저 시나리오</a> -->
<a href="salesmanagement/" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors">영업관리</a>
<a href="price/index.php" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors">가격정책</a>
<!-- Corporate Analysis Hamburger Menu -->
<div class="relative group">
<button class="p-2 rounded-lg text-slate-600 hover:bg-slate-100 transition-colors">
<i data-lucide="menu" class="w-5 h-5"></i>
</button>
<div class="absolute right-0 top-full mt-1 w-48 bg-white rounded-xl shadow-xl border border-slate-100 py-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 transform origin-top-right z-50">
<a href="etc/myoctopus.php" class="block px-4 py-2 text-sm text-slate-700 hover:bg-brand-50 hover:text-brand-600 font-medium">
문어이미지 선발
</a>
<a href="corp/kodata.php" class="block px-4 py-2 text-sm text-slate-700 hover:bg-brand-50 hover:text-brand-600 font-medium">
기업분석 한국평가데이터 (kodata)
</a>
<a href="coocon/index.php" class="block px-4 py-2 text-sm text-slate-700 hover:bg-brand-50 hover:text-brand-600 font-medium">
기업신용조회 쿠콘닷컴 (coocon)
</a>
</div>
</div>
<?php if (isset($_SESSION['userid']) && $_SESSION['userid'] != ''): ?>
<div class="flex items-center gap-2 ml-2">
<div class="w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center text-slate-500 font-bold border border-slate-300">
<?= mb_substr($_SESSION['name'], 0, 1) ?>
</div>
<span class="text-sm font-medium text-slate-700"><?= $_SESSION['name'] ?>님</span>
<a href="login/logout.php" class="px-3 py-1.5 bg-slate-100 text-slate-600 text-xs font-bold rounded hover:bg-slate-200 transition-colors border border-slate-200">로그아웃</a>
</div>
<?php else: ?>
<a href="login/login_form.php" class="px-4 py-2 bg-brand-600 text-white text-sm font-bold rounded-lg hover:bg-brand-700 transition-colors shadow-lg shadow-brand-200">
로그인
</a>
<?php endif; ?>
</div>
<!-- Mobile Hamburger Button -->
<button id="mobile-menu-button" class="md:hidden p-2 rounded-lg text-slate-600 hover:bg-slate-100 active:bg-slate-200 transition-colors touch-manipulation">
<i data-lucide="menu" class="w-6 h-6" id="menu-icon"></i>
<i data-lucide="x" class="w-6 h-6 hidden" id="close-icon"></i>
</button>
</div>
<!-- Mobile Menu -->
<div id="mobile-menu" class="hidden md:hidden border-t border-slate-200 py-4">
<div class="flex flex-col gap-3">
<a href="sales_scenario/" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors px-2 py-2 hover:bg-slate-50 rounded-lg" onclick="closeMobileMenu()">영업 시나리오</a>
<a href="sales_manager_scenario/" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors px-2 py-2 hover:bg-slate-50 rounded-lg" onclick="closeMobileMenu()">매니저 시나리오</a>
<a href="salesmanagement/" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors px-2 py-2 hover:bg-slate-50 rounded-lg" onclick="closeMobileMenu()">영업관리</a>
<a href="price/index.php" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors px-2 py-2 hover:bg-slate-50 rounded-lg" onclick="closeMobileMenu()">가격정책</a>
<a href="corp/kodata.php" class="text-sm font-medium text-slate-600 hover:text-brand-600 transition-colors px-2 py-2 hover:bg-slate-50 rounded-lg" onclick="closeMobileMenu()">기업분석</a>
<?php if (isset($_SESSION['userid']) && $_SESSION['userid'] != ''): ?>
<div class="flex items-center gap-2 px-2 py-2 border-t border-slate-200 mt-2 pt-3">
<div class="w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center text-slate-500 font-bold border border-slate-300">
<?= mb_substr($_SESSION['name'], 0, 1) ?>
</div>
<span class="text-sm font-medium text-slate-700 flex-1"><?= $_SESSION['name'] ?>님</span>
<a href="login/logout.php" class="px-3 py-1.5 bg-slate-100 text-slate-600 text-xs font-bold rounded hover:bg-slate-200 transition-colors border border-slate-200" onclick="closeMobileMenu()">로그아웃</a>
</div>
<?php else: ?>
<a href="login/login_form.php" class="px-4 py-2 bg-brand-600 text-white text-sm font-bold rounded-lg hover:bg-brand-700 transition-colors shadow-lg shadow-brand-200 text-center mt-2" onclick="closeMobileMenu()">
로그인
</a>
<?php endif; ?>
</div>
</div>
</div>
</nav>
<!-- Hero Section -->
<header class="relative bg-white pt-16 pb-20 lg:pt-24 lg:pb-28 overflow-hidden">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="text-center max-w-4xl mx-auto">
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-50 text-brand-700 text-xs font-semibold uppercase tracking-wider mb-6 animate-fade-in-up">
<i data-lucide="shield-check" class="w-4 h-4"></i>
CEO Management Solution
</div>
<h1 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-extrabold text-slate-900 tracking-tight mb-6 animate-fade-in-up delay-100 leading-tight">
<span class="whitespace-nowrap">직원 관리 도구가 아닙니다.</span><br />
<span class="text-transparent bg-clip-text bg-gradient-to-r from-brand-600 to-indigo-600 whitespace-nowrap">
대표님 경영 무기입니다.
</span>
</h1>
<p class="text-lg sm:text-xl text-slate-500 mb-10 leading-relaxed max-w-2xl mx-auto animate-fade-in-up delay-200">
SAM은 현장에 없어도, 현장을 다 보여줍니다. <br class="hidden sm:block"/>
대표님 손 안의 스마트 경영 계기판, SAM<br />
<strong>오직 CEO를 위한 시크릿 대시보드</strong>를 제안하십시오.
https://vimeo.com/manage/videos/1151273154
</p>
<!-- Main Hero Image -->
<div class="mt-16 relative z-10 animate-fade-in-up delay-300">
<div class="relative rounded-2xl overflow-hidden shadow-2xl border-4 border-white/50 bg-white">
<img src="img/sam_project.jpg" alt="SAM Project Dashboard" class="w-full h-auto object-cover">
<div class="absolute inset-0 bg-gradient-to-t from-slate-900/10 to-transparent pointer-events-none"></div>
</div>
<!-- Decorative Elements around image -->
<div class="absolute -top-10 -right-10 w-24 h-24 bg-brand-400 rounded-full mix-blend-multiply filter blur-2xl opacity-40 animate-blob"></div>
<div class="absolute -bottom-10 -left-10 w-24 h-24 bg-indigo-400 rounded-full mix-blend-multiply filter blur-2xl opacity-40 animate-blob animation-delay-2000"></div>
</div>
</div>
</div>
<!-- Background Decorations -->
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-full h-full z-0 pointer-events-none">
<div class="absolute top-20 left-10 w-72 h-72 bg-brand-200 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob"></div>
<div class="absolute top-20 right-10 w-72 h-72 bg-indigo-200 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-2000"></div>
<div class="absolute -bottom-8 left-1/2 w-72 h-72 bg-pink-200 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-4000"></div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div class="flex flex-col sm:flex-row items-center justify-between mb-8 gap-4">
<h2 class="text-2xl font-bold text-slate-900">영업 자료</h2>
<div id="filter-buttons" class="flex flex-wrap gap-2 justify-center">
<!-- Filter buttons injected by JS -->
</div>
</div>
<!-- Grid Container -->
<div id="assets-grid" class="grid grid-cols-1 md:grid-cols-3 gap-6 auto-rows-auto">
<!-- Cards injected by JS -->
</div>
<div id="empty-state" class="hidden text-center py-20 text-slate-400 col-span-3">
해당 카테고리에 자료가 없습니다.
</div>
</main>
<!-- Footer -->
<footer class="bg-white border-t border-slate-200 py-12 mt-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col md:flex-row justify-between items-center gap-6">
<p class="text-slate-500 text-sm">© 2025 CodeBridge-X Corp. 영업 관리</p>
<div class="flex gap-6">
<a href="#" class="text-slate-400 hover:text-slate-600">사내 전용 (대외비)</a>
<a href="#" class="text-slate-400 hover:text-slate-600">영업 스크립트</a>
<a href="#" class="text-slate-400 hover:text-slate-600">고객 지원</a>
</div>
</div>
</footer>
<!-- Modal Backdrop & Modal -->
<div id="modal-backdrop" class="fixed inset-0 bg-slate-900/50 backdrop-blur-sm z-50 hidden transition-opacity opacity-0" onclick="closeModal()"></div>
<div id="modal-container" class="fixed inset-0 z-50 flex items-center justify-center p-4 pointer-events-none hidden">
<!-- Modal Content injected by JS -->
</div>
<!-- Full Screen Viewer Overlay -->
<div id="fullscreen-view" onclick="closeFullscreen()">
<div class="fullscreen-close">
<i data-lucide="x" class="w-6 h-6 text-slate-900"></i>
</div>
<img id="fullscreen-img" src="" alt="Full size view" onclick="event.stopPropagation()">
</div>
<!-- PDF Viewer Modal -->
<div id="pdf-modal-backdrop" class="fixed inset-0 bg-slate-900/50 backdrop-blur-sm z-[70] hidden transition-opacity opacity-0" onclick="closePdfViewer()"></div>
<div id="pdf-modal-container" class="fixed inset-0 z-[70] flex items-center justify-center p-4 pointer-events-none hidden">
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-[95vw] h-[95vh] flex flex-col pointer-events-auto scale-95 opacity-0 transition-all duration-300" id="pdf-modal-card">
<div class="sticky top-0 bg-white/90 backdrop-blur-sm p-4 border-b border-slate-100 flex justify-between items-center z-10">
<h3 class="text-lg font-bold text-slate-900" id="pdf-modal-title">상세자료</h3>
<button onclick="closePdfViewer()" class="w-8 h-8 rounded-full bg-slate-50 hover:bg-slate-100 flex items-center justify-center text-slate-500 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="flex-1 overflow-hidden">
<iframe id="pdf-viewer-iframe" src="" class="w-full h-full border-0" frameborder="0"></iframe>
</div>
</div>
</div>
<script>
// 통일된 영업 자료 데이터 구조
// 모든 카드는 동일한 포맷: 이미지(4:3), 설명, 동영상, 오디오, 영업 스크립트
const ASSETS = [
{
id: '1',
title: '대표를 위한 무기',
image: 'img/sales1.jpg',
description: '기존 ERP는 직원의 관리 도구였지만, SAM은 대표님의 의사결정 무기입니다. 직원의 보고를 기다리지 마십시오.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1147875239?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="SAM__CEO를_위한_무기"></iframe></div>',
audio: 'm4a/sales1.m4a',
pdf: 'pdf/sales1.pdf',
script: "대표님, ERP나 MES 들어보셨죠? 보통 직원들이 입력하고 관리하는 도구입니다. 정작 대표님은 직원한테 보고를 받아야만 회사를 알 수 있죠. SAM은 반대입니다. 직원이 아니라 '대표님을 위한 무기'입니다. 외근 중이든 집이든, 대표님 폰에서 회사의 자금, 인력, 리스크가 한눈에 보입니다.",
tags: ['Pitch', 'Opener'],
},
{
id: '2',
title: 'CEO 시크릿 대시보드',
image: 'img/sales2.jpg',
description: 'CEO 시크릿 대시보드는 마치 고성능 전투기의 조종석 대시보드와 같습니다. 수많은 기계적 장치(직원들의 업무)가 뒤에서 복잡하게 돌아가더라도, 조종사(대표님)는 전방의 적기(세무 리스크)와 연료 잔량(자금 흐름) 등 승리를 위해 지금 당장 필요한 정보만 확인하며 최적의 의사결정을 내릴 수 있게 돕기 때문입니다.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1146972515?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="CEO 경영 비서, SAM"></iframe></div>',
audio: 'm4a/sales2.m4a',
pdf: 'pdf/sales2.pdf',
script: "특히 대표님들께서 가장 좋아하시는 기능이 있습니다. 외근 중에 회사에 큰 계약이 성사되거나 매출이 입금되면, 대표님 휴대폰에서만 경쾌하게 'SAM~' 하고 시그니처 알림음이 울립니다. 직원의 보고를 기다릴 필요 없이, 돈이 들어오는 순간을 즉시 느끼며 성취감을 맛보실 수 있습니다.",
tags: ['Demo', 'Dashboard', 'Finance'],
},
{
id: '3',
title: '20가지 고충 해결',
image: 'img/sales3.jpg',
description: "SAM을 도입하는 것은 유능한 경리 대리, 현장 팀장, 그리고 전담 비서까지 총 3명의 인재를 동시에 채용하는 것과 같은 경제적 효과를 가져옵니다. 이를 통해 대표님은 복잡한 관리 업무에서 해방되어 오직 확신을 가지고 경영에만 집중할 수 있는 환경을 갖게 됩니다. SAM은 마치 대표님의 모든 고민을 대신 짊어지고 24시간 깨어 있는 '디지털 전담 비서'**와 같습니다. 복잡하게 얽힌 실타래 같은 경영 고충들을 SAM이라는 날카로운 가위로 단번에 정리하여, 대표님이 오직 '성장'이라는 큰 그림에만 집중하실 수 있도록 돕는 든든한 조력자가 되어줄 것입니다.",
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1147890755?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="20가지 경영고충"></iframe></div>',
audio: 'm4a/sales3.m4a',
pdf: 'pdf/sales3.pdf',
script: "중소기업 대표님의 머릿속을 20가지로 정리해봤습니다. 직원 근태, 자금 압박, 세무 조사... 이 모든 걸 혼자 감당하고 계시지 않습니까? SAM은 단순 프로그램이 아니라, 이 20가지 리스크를 막아주는 방패입니다.",
tags: ['Pain Points', 'Solution'],
},
{
id: '4',
title: '모바일 & 감성 알림',
image: 'img/sales4.jpg',
description: "SAM의 모바일 기능을 비유하자면, 마치 '내 손안에 들어온 회사 전체 상황판'과 같습니다. 사무실에 앉아 있지 않아도 회사의 모든 숫자가 자동으로 맞춰지는 것을 확인하고, 기분 좋은 알림음을 통해 성장의 순간을 실시간으로 함께할 수 있기 때문입니다.",
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1147907223?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="모바일 & 감성 알림"></iframe></div>',
audio: 'm4a/sales4.m4a',
pdf: 'pdf/sales4.pdf',
script: "가장 인기 있는 기능입니다. 외근 나가 계실 때 불안하시죠? 직원이 큰 수주를 따오거나, 거래처에서 돈을 입금하면 대표님 폰에서 'SAM~' 하고 알림이 옵니다. 그 소리만 들으면 '아, 우리 회사 잘 돌아가고 있구나' 안심이 되실 겁니다.",
tags: ['Mobile', 'UX', 'Emotion'],
},
{
id: '5',
title: 'CEO들의 심리적 약점과 욕구',
image: 'img/sales5.jpg',
description: 'SAM 프로젝트의 핵심 영업 전략은 CEO들의 심리적 약점과 욕구(통제 욕구, 복잡한 것 회피, 비용 민감성)를 파고들어 설득력을 극대화하도록 재정비되었습니다.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1147912498?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="영업_전략_해부__CEO에게_파는_법"></iframe></div>',
audio: 'm4a/sales5.m4a',
pdf: 'pdf/sales5.pdf',
script: "1. 통제 욕구 및 불안감 자극/해소: 지각/무단결근 등 특이사항과 내일 나갈 돈(예상 부가세)을 미리 보여주어 통제감을 높여줍니다.\n2. 복잡한 것 회피: 모바일 중심의 '시크릿 모드'와 10초 사용을 강조하여 진입장벽을 낮춥니다.\n3. 비용 민감성: 월 30~50만 원으로 24시간 AI 경영 비서를 고용하는 가성비를 강조합니다.",
tags: ['Strategy', 'CEO Psychology', 'Sales Pitch'],
},
{
id: '6',
title: '인수인계 리스크, 자동화로 해결',
image: 'img/sales6.jpg',
description: '직원이 갑자기 퇴사해도 걱정 없습니다. 견적부터 발주, 출고까지 모든 이력이 클릭 한 번으로 자동 인수인계됩니다.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1147914271?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="인수인계 리스크, 자동화로 해결"></iframe></div>',
audio: 'm4a/sales6.m4a',
pdf: 'pdf/sales6.pdf',
script: "직원이 갑자기 그만둔다고 하면 눈앞이 캄캄하시죠? 파일 어디 있냐, 거래처 연락처 뭐냐... SAM을 쓰시면 그럴 일 없습니다. 모든 업무 기록이 서버에 남기 때문에, 후임자는 '클릭' 한 번이면 전임자의 모든 업무를 그대로 이어받습니다.",
tags: ['Automation', 'Management'],
},
{
id: '7',
title: '1. 대표님의 고민 (Pain Points)',
image: 'img/sales7.jpg',
description: '매출은 느는데 이익은 제자리? 직원과 현장을 100% 믿을 수 있나? 세금 낼 때마다 자금 계획이 꼬이나? 이는 정보 부재에서 오는 "전략적 리스크"입니다.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1148039484?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="CEO들의 심리적 약점과 욕구"></iframe></div>',
audio: 'm4a/sales7.m4a',
pdf: 'pdf/sales7.pdf',
script: "매출은 계속 오르는데, 왜 통장에 남는 돈은 없을까요? 직원들은 정말 열심히 하고 있는 걸까요? 세금 낼 때마다 목돈 마련하느라 허덕이시진 않나요? 더 많은 보고서가 아니라, 대표님 손안에 '진짜 정보'가 필요할 때입니다.",
tags: ['Pain Points', 'Risk', 'Needs'],
},
{
id: '8',
title: '2. 새로운 해법 (Solution)',
image: 'img/sales8.jpg',
description: 'SAM은 "실무자 관리 도구"가 아닌 "CEO 의사결정 도구"입니다. 복잡한 입력은 AI가, 대표님은 직관적인 신호등과 요약 카드만 확인하십시오.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1148042194?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="인수인계 리스크, 자동화로 해결"></iframe></div>',
audio: 'm4a/sales8.m4a',
pdf: 'pdf/sales8.pdf',
script: "기존 ERP는 관리자용이라 복잡하고 비쌉니다. SAM은 다릅니다. 오직 대표님을 위해 설계되었습니다. 복잡한 표 대신 신호등으로, PC 대신 모바일로, 수천만 원 구축비 대신 합리적 구독료로 제공합니다. 복잡한 건 AI에게 맡기고, 대표님은 흐름만 보십시오.",
tags: ['Solution', 'Differentiation', 'AI'],
},
{
id: '9',
title: '3. 핵심 기능 (Core Features)',
image: 'img/sales9.jpg',
description: '리스크 사전 방지(미수금, 재고), 자금 흐름 관리(예상 부가세, 한도 체크), 실시간 현장 통제(지각, AI 업무일지).',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1148045716?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="핵심 기능 (Core Features)"></iframe></div>',
audio: 'm4a/sales9.m4a',
pdf: 'pdf/sales9.pdf',
script: "A업체 미수금 3개월 경과, 접대비 한도 80% 소진, 오늘 지각자 3명... 대표님이 놓치기 쉬운 '리스크'만 골라서 붉은색 알림을 띄워드립니다. 사무실 밖에서도 현장과 자금이 한눈에 들어옵니다.",
tags: ['Features', 'Risk', 'Finance', 'Ops'],
},
{
id: '10',
title: '4. 도입 효과 (ROI)',
image: 'img/sales10.jpg',
description: '보고 시간 0분(실시간 확인), 단순 업무 80% 자동화, 의사결정 속도 즉시. 눈에 보이는 비용 절감과 경쟁력 강화를 경험하십시오.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1148058600?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="핵심 기능 (Core Features)"></iframe></div>',
audio: 'm4a/sales10.m4a',
pdf: 'pdf/sales10.pdf',
script: "직원이 보고서 만들어서 결재 올릴 때까지 기다리지 마십시오. SAM을 쓰면 보고 시간이 '0분'이 됩니다. 단순 반복 업무는 80% 자동화됩니다. 이게 바로 돈 버는 시스템입니다.",
tags: ['ROI', 'Efficiency', 'Automation'],
},
{
id: '11',
title: '5. 제안 (Investment)',
image: 'img/sales11.jpg',
description: '연 3,000만 원 경리 직원 채용 vs 월 30만 원 AI 비서. 24시간 잠들지 않는 AI를 신입사원 월급의 1/10도 안 되는 비용으로 고용하십시오.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1148061489?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="핵심 기능 (Core Features)"></iframe></div>',
audio: 'm4a/sales11.m4a',
pdf: 'pdf/sales11.pdf',
script: "사람 한 명 뽑으려면 3천만 원 듭니다. SAM은 월 30만 원입니다. 1/100 비용으로 24시간 잠들지 않고 실수도 없는 완벽한 AI 비서를 채용하시는 겁니다. 이건 지출이 아니라 가장 확실한 투자입니다.",
tags: ['Investment', 'Cost', 'Value'],
},
{
id: '12',
title: '6. 다음 단계 (Next Steps)',
image: 'img/sales12.jpg',
description: '백 번 설명보다 한 번의 경험이 낫습니다. 대표님 업종에 맞춘 "무료 진단 & 시연"과 "3일 무료 체험"을 신청하십시오.',
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1148063858?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="핵심 기능 (Core Features)"></iframe></div>',
audio: 'm4a/sales12.m4a',
pdf: 'pdf/sales12.pdf',
script: "우리 회사에 맞을까 고민하지 마세요. 대표님 업종에 딱 맞춘 대시보드를 미리 구성해서 보여드립니다. 3일만 직접 써보시면, 왜 SAM이 필수인지 바로 아실 겁니다.",
tags: ['Call to Action', 'Demo', 'Free Trial'],
},
{
id: '13',
title: 'SAM의 비교 분석',
image: 'img/sales13.jpg',
description: "SAM은 복잡한 기계실의 수많은 계기판(기존 ERP) 대신, 조종석 정면에 떠오르는 핵심 정보창(HUD)과 같아서, 경영자가 복잡한 수치에 매몰되지 않고 회사의 나아갈 방향을 즉시 결정할 수 있도록 돕습니다.",
video: '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1149068241?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="핵심 기능 (Core Features)"></iframe></div>',
audio: 'm4a/sales13.m4a',
pdf: 'pdf/sales13.pdf',
script: "기존 ERP가 직원용 '도구'였다면, **SAM은 대표님의 의사결정을 위한 '무기'입니다. 로그인 10초 만에 AI가 요약한 5대 핵심 지표를 파악하고, '돈 들어오는 소리'와 함께 실시간으로 회사를 통제하십시오. 보고서 대기 없는 'AI 경영 비서' SAM으로, 이제 복잡한 데이터가 아닌 오직 '경영'에만 집중할 때입니다",
tags: ['Comparison', 'AI', 'Efficiency'],
},
{
id: '14',
title: '품질인정제도 가이드 (영업 전략)',
image: 'img/sales14.jpg',
description: '2021년 강화된 자동방화셔터 품질인정제도에 따른 영업 대응 전략입니다. 법적 기준 변화를 기회로 만드는 핵심 인사이트를 제공합니다.',
url: 'etc/shutter.php',
script: "대표님, 최근 방화셔터 법규가 바뀐 것 알고 계시나요? 이제 단순히 셔터만 설치하는 게 아니라 '품질인정제도'를 통과한 제품만 시공이 가능합니다. 이 변화가 왜 대표님께 기회인지, 어떻게 리스크를 피할 수 있는지 이 가이드에서 핵심만 정리해 드립니다.",
tags: ['Strategy', 'Compliance', 'Sales Pitch'],
}
];
// Constants
const FILTERS = ['전체', 'CEO 설득', '데모'];
let activeFilter = '전체';
// DOM Elements
const gridEl = document.getElementById('assets-grid');
const filterContainer = document.getElementById('filter-buttons');
const emptyState = document.getElementById('empty-state');
const modalBackdrop = document.getElementById('modal-backdrop');
const modalContainer = document.getElementById('modal-container');
const toast = document.getElementById('toast');
// Initial Render
function init() {
renderFilters();
renderGrid();
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
}
// Filter Logic
function renderFilters() {
filterContainer.innerHTML = FILTERS.map(filter => `
<button
onclick="filterAssets('${filter}')"
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium transition-colors duration-200 whitespace-nowrap ${activeFilter === filter ? 'bg-slate-900 text-white shadow-md' : 'bg-white text-slate-600 hover:bg-slate-100 border border-transparent hover:border-slate-200'}"
>
${filter}
</button>
`).join('');
}
window.filterAssets = (filter) => {
activeFilter = filter;
renderFilters();
renderGrid();
lucide.createIcons();
};
function getFilteredAssets() {
if (activeFilter === '전체') return ASSETS;
return ASSETS.filter(asset => {
if (activeFilter === 'CEO 설득') return asset.tags.some(tag => ['Pitch', 'Opener', 'Pain Points', 'Solution', 'Closing', 'Risk', 'Needs', 'Differentiation', 'Investment', 'Cost', 'Value', 'Strategy'].includes(tag));
if (activeFilter === '데모') return asset.tags.some(tag => ['Demo', 'Dashboard', 'Video', 'Mobile', 'UX', 'Infra', 'Feature', 'Automation', 'Management'].includes(tag));
return true;
});
}
// Grid Render
function renderGrid() {
const assets = getFilteredAssets();
if (assets.length === 0) {
emptyState.classList.remove('hidden');
} else {
emptyState.classList.add('hidden');
}
gridEl.innerHTML = assets.map(asset => {
// [1] 이미지 영역 (실제 이미지 비율 계산)
let imageHtml = '';
if (asset.image) {
imageHtml = `
<div class="relative bg-slate-50 overflow-hidden group/img cursor-pointer border-b border-slate-100" onclick="openModal('${asset.id}')" data-asset-id="${asset.id}">
<img src="${asset.image}" alt="${asset.title}"
class="w-full h-auto object-cover transform group-hover/img:scale-105 transition-transform duration-700"
style="image-rendering: -webkit-optimize-contrast;"
onload="setImageAspectRatio(this)"
data-asset-id="${asset.id}">
<div class="absolute inset-0 bg-black/5 opacity-0 group-hover/img:opacity-100 transition-opacity flex items-center justify-center pointer-events-none">
<div class="bg-white/90 backdrop-blur p-2 rounded-full shadow-lg">
<i data-lucide="zoom-in" class="w-5 h-5 text-slate-700"></i>
</div>
</div>
</div>`;
} else {
// 이미지가 없을 때 아이콘 표시
let iconName = 'file-text';
if (asset.video) iconName = 'play-circle';
else if (asset.audio) iconName = 'mic';
imageHtml = `
<div class="relative aspect-[4/3] bg-gradient-to-br from-slate-100 to-slate-200 flex items-center justify-center border-b border-slate-100">
<div class="text-slate-300">
<i data-lucide="${iconName}" class="w-16 h-16 opacity-40"></i>
</div>
</div>`;
}
// [2] 정보 영역
return `
<div class="bg-white rounded-2xl border border-slate-200 shadow-sm hover:shadow-xl transition-all duration-500 overflow-hidden flex flex-col group h-full" onclick="openModal('${asset.id}')">
${imageHtml}
<div class="p-6 flex-grow flex flex-col">
<div class="flex items-center justify-between mb-3">
<div class="flex gap-2">
${asset.tags.map(tag => `<span class="text-slate-400 text-[10px] font-medium">#${tag}</span>`).join(' ')}
</div>
<button class="text-slate-300 hover:text-brand-500 transition-colors">
<i data-lucide="share-2" class="w-4 h-4"></i>
</button>
</div>
<h3 class="text-base sm:text-lg font-bold text-slate-900 mb-2 group-hover:text-brand-600 transition-colors break-keep leading-tight" style="word-break: keep-all; overflow-wrap: break-word;">${asset.title}</h3>
<div class="flex-grow">
<p class="text-slate-600 text-sm leading-relaxed mb-4 line-clamp-3">
${asset.description || ''}
</p>
</div>
<!-- 미디어 타입 표시 -->
<div class="mb-3 flex items-center gap-2 text-xs text-slate-400">
${asset.image ? '<span class="flex items-center gap-1"><i data-lucide="image" class="w-3 h-3"></i> 이미지</span>' : ''}
${asset.video ? '<span class="flex items-center gap-1"><i data-lucide="play-circle" class="w-3 h-3"></i> 동영상</span>' : ''}
${asset.audio ? '<span class="flex items-center gap-1"><i data-lucide="mic" class="w-3 h-3"></i> 팟캐스트</span>' : ''}
${asset.script ? '<span class="flex items-center gap-1"><i data-lucide="message-square" class="w-3 h-3"></i> 스크립트</span>' : ''}
</div>
<div class="mt-auto pt-4 border-t border-slate-50 flex items-center justify-between">
<button class="text-brand-600 text-xs font-bold hover:underline flex items-center gap-1">
상세 보기 <i data-lucide="chevron-right" class="w-3 h-3"></i>
</button>
<span class="text-[10px] text-slate-300 font-bold uppercase tracking-widest">SAM</span>
</div>
</div>
</div>
`;
}).join('');
}
// Modal Logic
window.openModal = (id) => {
const asset = ASSETS.find(a => a.id === id);
if (!asset) return;
// Generate content
const tagsHtml = asset.tags.map(tag => `<span class="px-2 py-1 rounded-md bg-slate-100 text-slate-500 text-xs font-medium">#${tag}</span>`).join('');
// 통일된 미디어 표시 구조
let mediaHtml = '';
// 1. 이미지 (실제 비율 계산)
if (asset.image) {
mediaHtml += `
<div class="mb-6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-5 rounded-full bg-brand-500"></div>
<h4 class="font-bold text-slate-900">이미지</h4>
</div>
<div class="relative group viewer bg-slate-50 rounded-xl overflow-hidden border border-slate-100">
<div class="absolute top-3 right-3 z-[60] flex gap-2 translate-y-2 opacity-0 group-hover:opacity-100 transition-all duration-300">
<button onclick="toggleNaturalSize(this)"
class="px-4 py-2 bg-white/95 backdrop-blur-md shadow-lg border border-slate-200 rounded-full text-xs font-bold text-brand-600 hover:bg-brand-600 hover:text-white transition-all flex items-center gap-2">
<i data-lucide="maximize" class="w-3.5 h-3.5"></i>
<span>원본 크기 보기</span>
</button>
</div>
<div class="img-full-container custom-scrollbar scroll-smooth w-full overflow-hidden">
<img src="${asset.image}"
id="modal-main-img-${asset.id}"
class="w-full h-auto object-contain rounded-xl img-zoom-target"
style="image-rendering: -webkit-optimize-contrast; image-rendering: crisp-edges;"
onload="setModalImageAspectRatio(this)">
</div>
</div>
</div>`;
}
// 2. 설명 (이미지 밑에 표시)
if (asset.description) {
mediaHtml += `
<div class="mb-6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-5 rounded-full bg-brand-500"></div>
<h4 class="font-bold text-slate-900">설명</h4>
</div>
<div class="p-4 bg-slate-50 rounded-xl border border-slate-100 text-slate-700 leading-relaxed">
${asset.description}
</div>
</div>`;
}
// 2. 동영상
if (asset.video) {
mediaHtml += `
<div class="mb-6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-5 rounded-full bg-brand-500"></div>
<h4 class="font-bold text-slate-900">동영상</h4>
</div>
<div class="aspect-video bg-slate-100 rounded-xl overflow-hidden relative z-0">
${asset.video}
</div>
</div>`;
}
// 3. 오디오 팟캐스트
if (asset.audio) {
mediaHtml += `
<div class="mb-6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-5 rounded-full bg-brand-500"></div>
<h4 class="font-bold text-slate-900">팟캐스트</h4>
</div>
<div class="bg-slate-900 rounded-xl p-8 text-center">
<div class="w-24 h-24 rounded-full bg-indigo-500 mx-auto mb-6 flex items-center justify-center shadow-lg">
<i data-lucide="mic" class="w-10 h-10 text-white"></i>
</div>
<h4 class="text-white font-bold text-xl mb-2">${asset.title}</h4>
<p class="text-slate-400 text-sm mb-6">SAM Strategy Podcast</p>
<audio controls class="w-full">
<source src="${asset.audio}" type="audio/mp4">
<source src="${asset.audio}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>
</div>`;
}
const modalContent = `
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-2xl max-h-[90vh] overflow-y-auto pointer-events-auto scale-95 opacity-0 transition-all duration-300" id="modal-card">
<div class="sticky top-0 bg-white/90 backdrop-blur-sm p-4 border-b border-slate-100 flex justify-between items-center z-10">
<div class="flex items-center gap-2">
<h3 class="text-base sm:text-lg font-bold text-slate-900 break-keep leading-tight" style="word-break: keep-all; overflow-wrap: break-word;">${asset.title}</h3>
</div>
<button onclick="closeModal()" class="w-8 h-8 rounded-full bg-slate-50 hover:bg-slate-100 flex items-center justify-center text-slate-500 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="p-6 sm:p-8">
${mediaHtml}
<!-- 영업 스크립트 -->
${asset.script ? `
<div class="mb-8">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-5 rounded-full bg-brand-500"></div>
<h4 class="font-bold text-slate-900">영업 스크립트</h4>
</div>
<div class="bg-indigo-50/50 p-5 rounded-xl border border-indigo-100 relative">
<i data-lucide="quote" class="w-5 h-5 text-indigo-200 absolute top-4 left-4"></i>
<p class="text-slate-800 leading-relaxed pl-6 relative z-10 font-medium whitespace-pre-line">"${asset.script}"</p>
</div>
</div>
` : ''}
<div class="flex flex-wrap gap-2 pt-6 border-t border-slate-100">
${tagsHtml}
</div>
</div>
<div class="p-4 border-t border-slate-100 bg-slate-50 rounded-b-2xl flex justify-end gap-3">
<button onclick="closeModal()" class="px-3 sm:px-4 py-2 rounded-lg bg-white border border-slate-200 text-slate-700 font-medium hover:bg-slate-50 transition-colors whitespace-nowrap text-sm sm:text-base">닫기</button>
${asset.url ? `
<a href="${asset.url}" class="px-3 sm:px-4 py-2 rounded-lg bg-brand-600 text-white font-medium hover:bg-brand-700 shadow-md transition-colors flex items-center gap-2 whitespace-nowrap text-sm sm:text-base">
<i data-lucide="external-link" class="w-4 h-4 flex-shrink-0"></i>
<span>품질인정제도 소개 →</span>
</a>
` : ''}
${asset.pdf ? `
<button onclick="openPdfViewer('${asset.id}')" class="px-3 sm:px-4 py-2 rounded-lg bg-brand-600 text-white font-medium hover:bg-brand-700 shadow-md transition-colors flex items-center gap-2 whitespace-nowrap text-sm sm:text-base">
<i data-lucide="file-text" class="w-4 h-4 flex-shrink-0"></i>
<span>상세자료 보기</span>
</button>
` : `
${!asset.url ? `
<button onclick="showDownloadToast(); closeModal()" class="px-3 sm:px-4 py-2 rounded-lg bg-brand-600 text-white font-medium hover:bg-brand-700 shadow-md transition-colors flex items-center gap-2 whitespace-nowrap text-sm sm:text-base">
<i data-lucide="download" class="w-4 h-4 flex-shrink-0"></i>
<span>자료 사용하기</span>
</button>
` : ''}
`}
</div>
</div>
`;
modalContainer.innerHTML = modalContent;
// Animation In
modalBackdrop.classList.remove('hidden');
modalContainer.classList.remove('hidden');
document.body.classList.add('no-scroll');
// Trigger reflow
void modalBackdrop.offsetWidth;
modalBackdrop.classList.remove('opacity-0');
const card = document.getElementById('modal-card');
card.classList.remove('scale-95', 'opacity-0');
lucide.createIcons();
};
window.closeModal = () => {
const card = document.getElementById('modal-card');
if (card) {
card.classList.add('scale-95', 'opacity-0');
}
modalBackdrop.classList.add('opacity-0');
setTimeout(() => {
modalBackdrop.classList.add('hidden');
modalContainer.classList.add('hidden');
document.body.classList.remove('no-scroll');
modalContainer.innerHTML = '';
}, 300);
};
// Toggle Image Natural Size (Now Full Screen Wide View)
window.toggleNaturalSize = (btn) => {
// 버튼의 부모 컨테이너에서 이미지 찾기
const container = btn.closest('.group.viewer') || btn.closest('.relative');
const img = container ? container.querySelector('img.img-zoom-target') : null;
if (!img) {
console.error('이미지를 찾을 수 없습니다.');
return;
}
const fsView = document.getElementById('fullscreen-view');
const fsImg = document.getElementById('fullscreen-img');
if (!fsView || !fsImg) {
console.error('풀스크린 뷰어를 찾을 수 없습니다.');
return;
}
fsImg.src = img.src;
fsView.style.display = 'flex';
document.body.classList.add('no-scroll');
lucide.createIcons();
};
window.closeFullscreen = () => {
const fsView = document.getElementById('fullscreen-view');
fsView.style.display = 'none';
// 모달이 열려있는 상태면 스크롤 제한 유지, 아니면 해제
if (document.getElementById('modal-backdrop').classList.contains('hidden')) {
document.body.classList.remove('no-scroll');
}
};
// PDF Viewer Functions
window.openPdfViewer = (id) => {
const asset = ASSETS.find(a => a.id === id);
if (!asset || !asset.pdf) return;
const pdfBackdrop = document.getElementById('pdf-modal-backdrop');
const pdfContainer = document.getElementById('pdf-modal-container');
const pdfCard = document.getElementById('pdf-modal-card');
const pdfIframe = document.getElementById('pdf-viewer-iframe');
const pdfTitle = document.getElementById('pdf-modal-title');
pdfTitle.textContent = asset.title;
// PDF를 Google Drive Viewer로 표시 (로컬 파일도 가능)
// 또는 직접 PDF 파일 경로 사용 (브라우저 지원 시)
const pdfUrl = asset.pdf;
pdfIframe.src = pdfUrl;
// Animation In
pdfBackdrop.classList.remove('hidden');
pdfContainer.classList.remove('hidden');
document.body.classList.add('no-scroll');
// Trigger reflow
void pdfBackdrop.offsetWidth;
pdfBackdrop.classList.remove('opacity-0');
pdfCard.classList.remove('scale-95', 'opacity-0');
lucide.createIcons();
};
window.closePdfViewer = () => {
const pdfBackdrop = document.getElementById('pdf-modal-backdrop');
const pdfContainer = document.getElementById('pdf-modal-container');
const pdfCard = document.getElementById('pdf-modal-card');
const pdfIframe = document.getElementById('pdf-viewer-iframe');
if (pdfCard) {
pdfCard.classList.add('scale-95', 'opacity-0');
}
pdfBackdrop.classList.add('opacity-0');
setTimeout(() => {
pdfBackdrop.classList.add('hidden');
pdfContainer.classList.add('hidden');
pdfIframe.src = '';
// 모달이 열려있는 상태면 스크롤 제한 유지, 아니면 해제
if (document.getElementById('modal-backdrop').classList.contains('hidden')) {
document.body.classList.remove('no-scroll');
}
}, 300);
};
// 카드 이미지 비율 계산 함수
window.setImageAspectRatio = (img) => {
if (img.naturalWidth && img.naturalHeight) {
const container = img.closest('[data-asset-id]');
if (container) {
container.style.aspectRatio = `${img.naturalWidth} / ${img.naturalHeight}`;
}
}
};
// 모달 이미지 비율 계산 함수
window.setModalImageAspectRatio = (img) => {
if (img.naturalWidth && img.naturalHeight) {
const container = img.closest('.img-full-container');
if (container) {
// 모달에서는 최대 높이 제한을 두고 비율 유지
const maxHeight = window.innerHeight * 0.6;
const aspectRatio = img.naturalWidth / img.naturalHeight;
const calculatedWidth = maxHeight * aspectRatio;
if (calculatedWidth > container.offsetWidth) {
img.style.width = '100%';
img.style.height = 'auto';
} else {
img.style.width = `${calculatedWidth}px`;
img.style.height = `${maxHeight}px`;
}
}
}
};
// Mobile Menu Functions
window.toggleMobileMenu = (e) => {
if (e) {
e.preventDefault();
e.stopPropagation();
}
const mobileMenu = document.getElementById('mobile-menu');
const menuIcon = document.getElementById('menu-icon');
const closeIcon = document.getElementById('close-icon');
if (!mobileMenu || !menuIcon || !closeIcon) {
console.error('Mobile menu elements not found');
return;
}
if (mobileMenu.classList.contains('hidden')) {
mobileMenu.classList.remove('hidden');
menuIcon.classList.add('hidden');
closeIcon.classList.remove('hidden');
} else {
mobileMenu.classList.add('hidden');
menuIcon.classList.remove('hidden');
closeIcon.classList.add('hidden');
}
// 아이콘 재생성
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
};
window.closeMobileMenu = () => {
const mobileMenu = document.getElementById('mobile-menu');
const menuIcon = document.getElementById('menu-icon');
const closeIcon = document.getElementById('close-icon');
if (mobileMenu && !mobileMenu.classList.contains('hidden')) {
mobileMenu.classList.add('hidden');
if (menuIcon) menuIcon.classList.remove('hidden');
if (closeIcon) closeIcon.classList.add('hidden');
}
};
// Mobile menu button event listeners
// 스크립트가 body 끝에 있으므로 DOM은 이미 로드됨
(function setupMobileMenuButton() {
const mobileMenuButton = document.getElementById('mobile-menu-button');
if (mobileMenuButton) {
// 터치 이벤트와 클릭 이벤트 모두 처리
let touchStartTime = 0;
mobileMenuButton.addEventListener('touchstart', (e) => {
touchStartTime = Date.now();
e.stopPropagation();
}, { passive: true });
mobileMenuButton.addEventListener('touchend', (e) => {
e.preventDefault();
e.stopPropagation();
// 빠른 터치만 처리 (300ms 이내)
if (Date.now() - touchStartTime < 300) {
toggleMobileMenu(e);
}
}, { passive: false });
mobileMenuButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
toggleMobileMenu(e);
});
}
})();
// Close mobile menu when clicking outside
document.addEventListener('click', (e) => {
const mobileMenu = document.getElementById('mobile-menu');
const mobileMenuButton = document.getElementById('mobile-menu-button');
if (mobileMenu && mobileMenuButton &&
!mobileMenu.classList.contains('hidden') &&
!mobileMenu.contains(e.target) &&
!mobileMenuButton.contains(e.target)) {
closeMobileMenu();
}
});
// Close mobile menu on touch outside (for mobile)
document.addEventListener('touchstart', (e) => {
const mobileMenu = document.getElementById('mobile-menu');
const mobileMenuButton = document.getElementById('mobile-menu-button');
if (mobileMenu && mobileMenuButton &&
!mobileMenu.classList.contains('hidden') &&
!mobileMenu.contains(e.target) &&
!mobileMenuButton.contains(e.target)) {
closeMobileMenu();
}
});
// Initialize
init();
</script>
<script src="https://player.vimeo.com/api/player.js"></script>
</body>
</html>