455 lines
23 KiB
Plaintext
455 lines
23 KiB
Plaintext
<!-- Portfolio detail page content starts here -->
|
|
<% 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">
|
|
<link href="/css/fixes.css" rel="stylesheet">
|
|
|
|
|
|
<!-- 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>
|
|
|
|
<!-- Portfolio detail page content ends here -->
|
|
|
|
<!-- 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;
|
|
}
|
|
%> |