Files
sst_site/.history/views/portfolio-detail_20251019164427.ejs
2025-10-19 18:27:00 +09:00

472 lines
24 KiB
Plaintext

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= portfolio.title %> - SmartSolTech 포트폴리오</title>
<!-- SEO Meta Tags -->
<meta name="description" content="<%= portfolio.seo?.metaDescription || portfolio.shortDescription || portfolio.description %>">
<meta name="keywords" content="<%= portfolio.seo?.keywords?.join(', ') || portfolio.technologies?.join(', ') %>">
<!-- Open Graph -->
<meta property="og:title" content="<%= portfolio.title %> - SmartSolTech">
<meta property="og:description" content="<%= portfolio.shortDescription || portfolio.description %>">
<meta property="og:type" content="article">
<% if (portfolio.images && portfolio.images.length > 0) { %>
<meta property="og:image" content="<%= portfolio.images.find(img => img.isPrimary)?.url || portfolio.images[0].url %>">
<% } %>
<!-- PWA -->
<meta name="theme-color" content="#3B82F6">
<link rel="manifest" href="/manifest.json">
<link rel="apple-touch-icon" href="/images/icons/icon-192x192.png">
<!-- Styles -->
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
<link href="https://unpkg.com/swiper@8/swiper-bundle.min.css" rel="stylesheet">
<link href="/css/main.css" rel="stylesheet">
</head>
<body>
<%- include('partials/navigation') %>
<!-- Portfolio Header -->
<section class="pt-20 pb-12 bg-gradient-to-br from-gray-900 via-blue-900 to-purple-900">
<div class="container mx-auto px-4">
<!-- Breadcrumb -->
<nav class="flex text-white text-sm mb-8" data-aos="fade-up">
<a href="/" class="hover:text-blue-300 transition-colors">홈</a>
<span class="mx-2">/</span>
<a href="/portfolio" class="hover:text-blue-300 transition-colors">포트폴리오</a>
<span class="mx-2">/</span>
<span class="text-blue-300"><%= portfolio.title %></span>
</nav>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
<!-- Project Info -->
<div class="text-white" data-aos="fade-right">
<div class="flex items-center gap-4 mb-4">
<span class="bg-blue-600 text-white px-4 py-2 rounded-full text-sm font-semibold">
<%= getCategoryName(portfolio.category) %>
</span>
<% if (portfolio.featured) { %>
<span class="bg-yellow-500 text-white px-3 py-1 rounded-full text-xs font-bold">
<i class="fas fa-star"></i> FEATURED
</span>
<% } %>
<% if (portfolio.status === 'completed') { %>
<span class="bg-green-500 text-white px-3 py-1 rounded-full text-xs font-semibold">
<i class="fas fa-check"></i> 완료
</span>
<% } else if (portfolio.status === 'in-progress') { %>
<span class="bg-orange-500 text-white px-3 py-1 rounded-full text-xs font-semibold">
<i class="fas fa-cog fa-spin"></i> 진행 중
</span>
<% } %>
</div>
<h1 class="text-4xl md:text-5xl font-bold mb-6">
<%= portfolio.title %>
</h1>
<p class="text-xl text-gray-300 mb-8 leading-relaxed">
<%= portfolio.description %>
</p>
<!-- Project Stats -->
<div class="grid grid-cols-3 gap-6 mb-8">
<div class="text-center">
<div class="text-2xl font-bold text-blue-300"><%= portfolio.viewCount || 0 %></div>
<div class="text-sm text-gray-400">조회수</div>
</div>
<div class="text-center">
<div class="text-2xl font-bold text-red-300"><%= portfolio.likes || 0 %></div>
<div class="text-sm text-gray-400">좋아요</div>
</div>
<div class="text-center">
<div class="text-2xl font-bold text-yellow-300">
<%= portfolio.completedAt ? new Date(portfolio.completedAt).getFullYear() : new Date().getFullYear() %>
</div>
<div class="text-sm text-gray-400">완료년도</div>
</div>
</div>
<!-- Action Buttons -->
<div class="flex flex-col sm:flex-row gap-4">
<% if (portfolio.projectUrl) { %>
<a href="<%= portfolio.projectUrl %>"
target="_blank"
rel="noopener noreferrer"
class="bg-white text-blue-900 px-6 py-3 rounded-full font-semibold hover:bg-gray-100 transition-colors flex items-center justify-center">
<i class="fas fa-external-link-alt mr-2"></i>
프로젝트 보기
</a>
<% } %>
<button id="like-btn"
class="border-2 border-white text-white px-6 py-3 rounded-full font-semibold hover:bg-white hover:text-blue-900 transition-colors flex items-center justify-center">
<i class="fas fa-heart mr-2"></i>
좋아요 (<span id="like-count"><%= portfolio.likes || 0 %></span>)
</button>
</div>
</div>
<!-- Project Preview Image -->
<div class="relative" data-aos="fade-left">
<% if (portfolio.images && portfolio.images.length > 0) { %>
<div class="relative rounded-2xl overflow-hidden shadow-2xl">
<img src="<%= portfolio.images.find(img => img.isPrimary)?.url || portfolio.images[0].url %>"
alt="<%= portfolio.title %>"
class="w-full h-auto max-h-96 object-cover">
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent"></div>
</div>
<% } else { %>
<div class="w-full h-96 bg-gradient-to-br from-blue-400 to-purple-500 rounded-2xl flex items-center justify-center">
<i class="fas fa-code text-white text-6xl opacity-50"></i>
</div>
<% } %>
</div>
</div>
</div>
</section>
<!-- Project Details -->
<section class="section-padding">
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-12">
<!-- Main Content -->
<div class="lg:col-span-2">
<!-- Project Images Gallery -->
<% if (portfolio.images && portfolio.images.length > 1) { %>
<div class="mb-12" data-aos="fade-up">
<h2 class="text-3xl font-bold text-gray-900 mb-6">프로젝트 갤러리</h2>
<!-- Swiper -->
<div class="swiper portfolio-swiper">
<div class="swiper-wrapper">
<% portfolio.images.forEach(image => { %>
<div class="swiper-slide">
<div class="relative rounded-xl overflow-hidden shadow-lg">
<img src="<%= image.url %>"
alt="<%= image.alt || portfolio.title %>"
class="w-full h-64 md:h-80 object-cover">
<div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4">
<p class="text-white text-sm"><%= image.alt || portfolio.title %></p>
</div>
</div>
</div>
<% }) %>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
<% } %>
<!-- Project Description -->
<div class="mb-12" data-aos="fade-up">
<h2 class="text-3xl font-bold text-gray-900 mb-6">프로젝트 개요</h2>
<div class="prose max-w-none text-gray-600 leading-relaxed">
<%= portfolio.description %>
</div>
</div>
<!-- Technologies Used -->
<% if (portfolio.technologies && portfolio.technologies.length > 0) { %>
<div class="mb-12" data-aos="fade-up">
<h2 class="text-3xl font-bold text-gray-900 mb-6">사용된 기술</h2>
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<% portfolio.technologies.forEach(tech => { %>
<div class="bg-gradient-to-r from-blue-50 to-purple-50 border border-blue-200 rounded-lg p-4 text-center hover:shadow-md transition-shadow">
<div class="font-semibold text-gray-800"><%= tech %></div>
</div>
<% }) %>
</div>
</div>
<% } %>
<!-- Share Section -->
<div class="border-t pt-8" data-aos="fade-up">
<h3 class="text-xl font-bold text-gray-900 mb-4">이 프로젝트 공유하기</h3>
<div class="flex gap-4">
<button onclick="shareOnSocial('facebook')"
class="bg-blue-600 text-white p-3 rounded-full hover:bg-blue-700 transition-colors">
<i class="fab fa-facebook text-lg"></i>
</button>
<button onclick="shareOnSocial('twitter')"
class="bg-blue-400 text-white p-3 rounded-full hover:bg-blue-500 transition-colors">
<i class="fab fa-twitter text-lg"></i>
</button>
<button onclick="shareOnSocial('linkedin')"
class="bg-blue-700 text-white p-3 rounded-full hover:bg-blue-800 transition-colors">
<i class="fab fa-linkedin text-lg"></i>
</button>
<button onclick="copyToClipboard()"
class="bg-gray-600 text-white p-3 rounded-full hover:bg-gray-700 transition-colors">
<i class="fas fa-link text-lg"></i>
</button>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="lg:col-span-1">
<!-- Project Info -->
<div class="bg-white rounded-2xl shadow-lg p-6 mb-8" data-aos="fade-up">
<h3 class="text-xl font-bold text-gray-900 mb-6">프로젝트 정보</h3>
<div class="space-y-4">
<% if (portfolio.clientName) { %>
<div>
<div class="text-sm text-gray-500 font-medium">클라이언트</div>
<div class="text-gray-900"><%= portfolio.clientName %></div>
</div>
<% } %>
<div>
<div class="text-sm text-gray-500 font-medium">카테고리</div>
<div class="text-gray-900"><%= getCategoryName(portfolio.category) %></div>
</div>
<% if (portfolio.completedAt) { %>
<div>
<div class="text-sm text-gray-500 font-medium">완료일</div>
<div class="text-gray-900">
<%= new Date(portfolio.completedAt).toLocaleDateString('ko-KR') %>
</div>
</div>
<% } %>
<% if (portfolio.projectUrl) { %>
<div>
<div class="text-sm text-gray-500 font-medium">프로젝트 URL</div>
<a href="<%= portfolio.projectUrl %>"
target="_blank"
rel="noopener noreferrer"
class="text-blue-600 hover:underline break-all">
<%= portfolio.projectUrl %>
</a>
</div>
<% } %>
</div>
</div>
<!-- Contact CTA -->
<div class="bg-gradient-to-br from-blue-600 to-purple-600 rounded-2xl shadow-lg p-6 text-white" data-aos="fade-up">
<h3 class="text-xl font-bold mb-4">비슷한 프로젝트가 필요하신가요?</h3>
<p class="text-blue-100 mb-6">
이런 프로젝트에 관심이 있으시다면 언제든 연락주세요.
무료 상담을 통해 최적의 솔루션을 제안해드리겠습니다.
</p>
<div class="space-y-3">
<a href="/contact"
class="block w-full bg-white text-blue-600 text-center py-3 rounded-lg font-semibold hover:bg-gray-100 transition-colors">
프로젝트 문의하기
</a>
<a href="/calculator"
class="block w-full border-2 border-white text-white text-center py-3 rounded-lg font-semibold hover:bg-white hover:text-blue-600 transition-colors">
비용 계산하기
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Related Projects -->
<section class="section-padding bg-gray-50">
<div class="container mx-auto px-4">
<div class="text-center mb-12" data-aos="fade-up">
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
관련 프로젝트
</h2>
<p class="text-xl text-gray-600">
비슷한 카테고리의 다른 프로젝트들도 확인해보세요
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<% if (relatedProjects && relatedProjects.length > 0) { %>
<% relatedProjects.forEach((project, index) => { %>
<div class="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2"
data-aos="fade-up"
data-aos-delay="<%= index * 100 %>">
<div class="relative h-48 overflow-hidden">
<% if (project.images && project.images.length > 0) { %>
<img src="<%= project.images.find(img => img.isPrimary)?.url || project.images[0].url %>"
alt="<%= project.title %>"
class="w-full h-full object-cover transition-transform duration-300 hover:scale-110">
<% } else { %>
<div class="w-full h-full bg-gradient-to-br from-blue-400 to-purple-500 flex items-center justify-center">
<i class="fas fa-code text-white text-3xl opacity-50"></i>
</div>
<% } %>
</div>
<div class="p-6">
<h3 class="text-xl font-bold text-gray-900 mb-2 line-clamp-1">
<%= project.title %>
</h3>
<p class="text-gray-600 mb-4 line-clamp-2">
<%= project.shortDescription || project.description %>
</p>
<a href="/portfolio/<%= project._id %>"
class="text-blue-600 font-semibold hover:underline">
자세히 보기 →
</a>
</div>
</div>
<% }) %>
<% } else { %>
<div class="col-span-full text-center py-8">
<p class="text-gray-500">관련 프로젝트가 없습니다.</p>
</div>
<% } %>
</div>
</div>
</section>
<%- include('partials/footer') %>
<!-- Scripts -->
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
<script src="https://unpkg.com/swiper@8/swiper-bundle.min.js"></script>
<script src="/js/main.js"></script>
<script>
// Initialize Swiper
if (document.querySelector('.portfolio-swiper')) {
const swiper = new Swiper('.portfolio-swiper', {
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
autoplay: {
delay: 5000,
},
breakpoints: {
640: {
slidesPerView: 1,
},
768: {
slidesPerView: 1,
},
1024: {
slidesPerView: 1,
},
}
});
}
// Like functionality
document.getElementById('like-btn').addEventListener('click', async function() {
try {
const response = await fetch(`/api/portfolio/<%= portfolio._id %>/like`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
document.getElementById('like-count').textContent = result.likes;
this.classList.add('animate-pulse');
setTimeout(() => {
this.classList.remove('animate-pulse');
}, 1000);
}
} catch (error) {
console.error('Error liking project:', error);
}
});
// Social sharing
function shareOnSocial(platform) {
const url = encodeURIComponent(window.location.href);
const title = encodeURIComponent('<%= portfolio.title %>');
const description = encodeURIComponent('<%= portfolio.shortDescription || portfolio.description %>');
let shareUrl = '';
switch(platform) {
case 'facebook':
shareUrl = `https://www.facebook.com/sharer/sharer.php?u=${url}`;
break;
case 'twitter':
shareUrl = `https://twitter.com/intent/tweet?url=${url}&text=${title}`;
break;
case 'linkedin':
shareUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${url}`;
break;
}
if (shareUrl) {
window.open(shareUrl, '_blank', 'width=600,height=400');
}
}
// Copy link to clipboard
function copyToClipboard() {
navigator.clipboard.writeText(window.location.href).then(function() {
// Show toast message
const toast = document.createElement('div');
toast.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg z-50';
toast.textContent = '링크가 복사되었습니다!';
document.body.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 3000);
}).catch(function(err) {
console.error('Error copying to clipboard:', err);
});
}
// Update view count
fetch(`/api/portfolio/<%= portfolio._id %>/view`, {
method: 'POST'
}).catch(err => console.error('Error updating view count:', err));
// Category name helper
function getCategoryName(category) {
const categoryNames = {
'web-development': '웹 개발',
'mobile-app': '모바일 앱',
'ui-ux-design': 'UI/UX 디자인',
'branding': '브랜딩',
'marketing': '디지털 마케팅'
};
return categoryNames[category] || category;
}
</script>
<%
// Helper function for category names
function getCategoryName(category) {
const categoryNames = {
'web-development': '웹 개발',
'mobile-app': '모바일 앱',
'ui-ux-design': 'UI/UX 디자인',
'branding': '브랜딩',
'marketing': '디지털 마케팅'
};
return categoryNames[category] || category;
}
%>
</body>
</html>