297 lines
16 KiB
Plaintext
297 lines
16 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>포트폴리오 - SmartSolTech</title>
|
|
|
|
<!-- SEO Meta Tags -->
|
|
<meta name="description" content="SmartSolTech의 다양한 프로젝트와 성공 사례를 확인해보세요. 웹 개발, 모바일 앱, UI/UX 디자인 포트폴리오.">
|
|
<meta name="keywords" content="포트폴리오, 웹 개발, 모바일 앱, UI/UX 디자인, 프로젝트, SmartSolTech">
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:title" content="포트폴리오 - SmartSolTech">
|
|
<meta property="og:description" content="SmartSolTech의 다양한 프로젝트와 성공 사례">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:url" content="<%= `${req.protocol}://${req.get('host')}/portfolio` %>">
|
|
|
|
<!-- 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="/css/main.css" rel="stylesheet">
|
|
</head>
|
|
<body>
|
|
<%- include('partials/navigation') %>
|
|
|
|
<!-- Portfolio Hero Section -->
|
|
<section class="hero-section bg-gradient-to-br from-blue-600 via-purple-600 to-blue-800 pt-20">
|
|
<div class="container mx-auto px-4 py-20 text-center text-white">
|
|
<h1 class="text-5xl md:text-6xl font-bold mb-6" data-aos="fade-up">
|
|
우리의 <span class="text-yellow-300">포트폴리오</span>
|
|
</h1>
|
|
<p class="text-xl md:text-2xl mb-8 opacity-90" data-aos="fade-up" data-aos-delay="200">
|
|
혁신적인 프로젝트와 창의적인 솔루션들을 만나보세요
|
|
</p>
|
|
<div class="flex flex-wrap justify-center gap-4" data-aos="fade-up" data-aos-delay="400">
|
|
<button class="filter-btn bg-white text-blue-600 px-6 py-3 rounded-full font-semibold hover:bg-blue-50 transition-colors active" data-filter="all">
|
|
전체
|
|
</button>
|
|
<button class="filter-btn bg-blue-700 text-white px-6 py-3 rounded-full font-semibold hover:bg-blue-800 transition-colors" data-filter="web-development">
|
|
웹 개발
|
|
</button>
|
|
<button class="filter-btn bg-blue-700 text-white px-6 py-3 rounded-full font-semibold hover:bg-blue-800 transition-colors" data-filter="mobile-app">
|
|
모바일 앱
|
|
</button>
|
|
<button class="filter-btn bg-blue-700 text-white px-6 py-3 rounded-full font-semibold hover:bg-blue-800 transition-colors" data-filter="ui-ux-design">
|
|
UI/UX 디자인
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Portfolio Grid -->
|
|
<section class="section-padding bg-gray-50">
|
|
<div class="container mx-auto px-4">
|
|
<div id="portfolio-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
<% if (portfolioItems && portfolioItems.length > 0) { %>
|
|
<% portfolioItems.forEach((item, index) => { %>
|
|
<div class="portfolio-item bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2"
|
|
data-category="<%= item.category %>"
|
|
data-aos="fade-up"
|
|
data-aos-delay="<%= index * 100 %>">
|
|
|
|
<!-- Project Image -->
|
|
<div class="relative overflow-hidden h-64">
|
|
<% if (item.images && item.images.length > 0) { %>
|
|
<img src="<%= item.images.find(img => img.isPrimary)?.url || item.images[0].url || '/images/placeholder-project.jpg' %>"
|
|
alt="<%= item.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-4xl opacity-50"></i>
|
|
</div>
|
|
<% } %>
|
|
|
|
<!-- Category Badge -->
|
|
<div class="absolute top-4 left-4">
|
|
<span class="bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-semibold">
|
|
<%= getCategoryName(item.category) %>
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Featured Badge -->
|
|
<% if (item.featured) { %>
|
|
<div class="absolute top-4 right-4">
|
|
<span class="bg-yellow-500 text-white px-2 py-1 rounded-full text-xs font-bold">
|
|
<i class="fas fa-star"></i> FEATURED
|
|
</span>
|
|
</div>
|
|
<% } %>
|
|
|
|
<!-- Overlay -->
|
|
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-300 flex items-center justify-center">
|
|
<a href="/portfolio/<%= item._id %>" class="bg-white text-gray-900 px-6 py-3 rounded-full font-semibold hover:bg-gray-100 transition-colors">
|
|
자세히 보기
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Project Info -->
|
|
<div class="p-6">
|
|
<h3 class="text-xl font-bold text-gray-900 mb-3 line-clamp-2">
|
|
<%= item.title %>
|
|
</h3>
|
|
<p class="text-gray-600 mb-4 line-clamp-3">
|
|
<%= item.shortDescription || item.description %>
|
|
</p>
|
|
|
|
<!-- Technologies -->
|
|
<div class="flex flex-wrap gap-2 mb-4">
|
|
<% if (item.technologies && item.technologies.length > 0) { %>
|
|
<% item.technologies.slice(0, 3).forEach(tech => { %>
|
|
<span class="bg-gray-100 text-gray-600 px-2 py-1 rounded text-xs font-medium">
|
|
<%= tech %>
|
|
</span>
|
|
<% }) %>
|
|
<% if (item.technologies.length > 3) { %>
|
|
<span class="bg-gray-100 text-gray-600 px-2 py-1 rounded text-xs font-medium">
|
|
+<%= item.technologies.length - 3 %>
|
|
</span>
|
|
<% } %>
|
|
<% } %>
|
|
</div>
|
|
|
|
<!-- Client & Stats -->
|
|
<div class="flex items-center justify-between text-sm text-gray-500">
|
|
<div class="flex items-center">
|
|
<% if (item.clientName) { %>
|
|
<i class="fas fa-user mr-1"></i>
|
|
<%= item.clientName %>
|
|
<% } %>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<span class="flex items-center">
|
|
<i class="fas fa-eye mr-1"></i>
|
|
<%= item.viewCount || 0 %>
|
|
</span>
|
|
<span class="flex items-center">
|
|
<i class="fas fa-heart mr-1 text-red-400"></i>
|
|
<%= item.likes || 0 %>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Button -->
|
|
<div class="mt-4 pt-4 border-t border-gray-100">
|
|
<a href="/portfolio/<%= item._id %>" class="block w-full bg-blue-600 text-white text-center py-2 rounded-lg hover:bg-blue-700 transition-colors font-semibold">
|
|
프로젝트 상세보기
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% }) %>
|
|
<% } else { %>
|
|
<div class="col-span-full text-center py-12">
|
|
<i class="fas fa-folder-open text-6xl text-gray-300 mb-4"></i>
|
|
<h3 class="text-2xl font-bold text-gray-500 mb-2">아직 포트폴리오가 없습니다</h3>
|
|
<p class="text-gray-400">곧 멋진 프로젝트들을 공개할 예정입니다!</p>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
|
|
<!-- Load More Button -->
|
|
<% if (portfolioItems && portfolioItems.length >= 9) { %>
|
|
<div class="text-center mt-12" data-aos="fade-up">
|
|
<button id="load-more-btn" class="bg-blue-600 text-white px-8 py-3 rounded-full hover:bg-blue-700 transition-colors font-semibold">
|
|
더 많은 프로젝트 보기
|
|
</button>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- CTA Section -->
|
|
<section class="section-padding bg-gradient-to-r from-blue-600 to-purple-600 text-white">
|
|
<div class="container mx-auto px-4 text-center">
|
|
<h2 class="text-3xl md:text-4xl font-bold mb-6" data-aos="fade-up">
|
|
다음 프로젝트의 주인공이 되어보세요
|
|
</h2>
|
|
<p class="text-xl mb-8 opacity-90" data-aos="fade-up" data-aos-delay="200">
|
|
우리와 함께 혁신적인 디지털 솔루션을 만들어보세요
|
|
</p>
|
|
<div class="flex flex-col sm:flex-row gap-4 justify-center" data-aos="fade-up" data-aos-delay="400">
|
|
<a href="/contact" class="bg-white text-blue-600 px-8 py-3 rounded-full hover:bg-gray-100 transition-colors font-semibold">
|
|
프로젝트 문의하기
|
|
</a>
|
|
<a href="/calculator" class="border-2 border-white text-white px-8 py-3 rounded-full hover:bg-white hover:text-blue-600 transition-colors font-semibold">
|
|
비용 계산하기
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<%- include('partials/footer') %>
|
|
|
|
<!-- Scripts -->
|
|
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
|
<script src="/js/main.js"></script>
|
|
|
|
<script>
|
|
// Portfolio filtering functionality
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const filterButtons = document.querySelectorAll('.filter-btn');
|
|
const portfolioItems = document.querySelectorAll('.portfolio-item');
|
|
|
|
filterButtons.forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
const filter = button.getAttribute('data-filter');
|
|
|
|
// Update active button
|
|
filterButtons.forEach(btn => {
|
|
btn.classList.remove('active', 'bg-white', 'text-blue-600');
|
|
btn.classList.add('bg-blue-700', 'text-white');
|
|
});
|
|
button.classList.add('active', 'bg-white', 'text-blue-600');
|
|
button.classList.remove('bg-blue-700', 'text-white');
|
|
|
|
// Filter items
|
|
portfolioItems.forEach(item => {
|
|
const itemCategory = item.getAttribute('data-category');
|
|
if (filter === 'all' || itemCategory === filter) {
|
|
item.style.display = 'block';
|
|
item.classList.remove('opacity-0');
|
|
item.classList.add('opacity-100');
|
|
} else {
|
|
item.classList.remove('opacity-100');
|
|
item.classList.add('opacity-0');
|
|
setTimeout(() => {
|
|
if (item.classList.contains('opacity-0')) {
|
|
item.style.display = 'none';
|
|
}
|
|
}, 300);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Load more functionality
|
|
const loadMoreBtn = document.getElementById('load-more-btn');
|
|
if (loadMoreBtn) {
|
|
loadMoreBtn.addEventListener('click', async () => {
|
|
try {
|
|
const currentItems = portfolioItems.length;
|
|
const response = await fetch(`/api/portfolio?offset=${currentItems}&limit=6`);
|
|
const data = await response.json();
|
|
|
|
if (data.success && data.portfolioItems.length > 0) {
|
|
// Add new items to grid
|
|
// This would require server-side rendering or client-side templating
|
|
// For now, we'll just hide the button
|
|
if (data.portfolioItems.length < 6) {
|
|
loadMoreBtn.style.display = 'none';
|
|
}
|
|
} else {
|
|
loadMoreBtn.style.display = 'none';
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading more portfolio items:', error);
|
|
loadMoreBtn.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Category name mapping
|
|
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> |