feat: Реализован полный CRUD для админ-панели и улучшена функциональность

- Portfolio CRUD: добавление, редактирование, удаление, переключение публикации
- Services CRUD: полное управление услугами с возможностью активации/деактивации
- Banner system: новая модель Banner с CRUD операциями и аналитикой кликов
- Telegram integration: расширенные настройки бота, обнаружение чатов, отправка сообщений
- Media management: улучшенная загрузка файлов с оптимизацией изображений и превью
- UI improvements: обновлённые админ-панели с rich-text редактором и drag&drop загрузкой
- Database: добавлена таблица banners с полями для баннеров и аналитики
This commit is contained in:
2025-10-22 20:32:16 +09:00
parent 150891b29d
commit 9477ff6de0
69 changed files with 11451 additions and 2321 deletions

View File

@@ -1,17 +1,17 @@
<!DOCTYPE html>
<html lang="ko">
<html lang="<%= locale || 'ko' %>" class="<%= theme === 'dark' ? 'dark' : '' %>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>포트폴리오 - SmartSolTech</title>
<title><%- __('portfolio.meta.title') %> - SmartSolTech</title>
<!-- SEO Meta Tags -->
<meta name="description" content="SmartSolTech의 다양한 프로젝트와 성공 사례를 확인해보세요. 웹 개발, 모바일 앱, UI/UX 디자인 포트폴리오.">
<meta name="keywords" content="포트폴리오, 웹 개발, 모바일 앱, UI/UX 디자인, 프로젝트, SmartSolTech">
<meta name="description" content="<%- __('portfolio.meta.description') %>">
<meta name="keywords" content="<%- __('portfolio.meta.keywords') %>">
<!-- Open Graph -->
<meta property="og:title" content="포트폴리오 - SmartSolTech">
<meta property="og:description" content="SmartSolTech의 다양한 프로젝트와 성공 사례">
<meta property="og:title" content="<%- __('portfolio.meta.og_title') %>">
<meta property="og:description" content="<%- __('portfolio.meta.og_description') %>">
<meta property="og:type" content="website">
<!-- PWA -->
@@ -24,31 +24,33 @@
<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">
<link href="/css/fixes.css" rel="stylesheet">
<link href="/css/dark-theme.css" rel="stylesheet">
</head>
<body>
<body class="font-sans dark:bg-gray-900 dark:text-gray-100">
<%- 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">
<section class="hero-section-compact bg-gradient-to-br from-blue-600 via-purple-600 to-blue-800">
<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>
<%- __('portfolio_page.title') %>
</h1>
<p class="text-xl md:text-2xl mb-8 opacity-90" data-aos="fade-up" data-aos-delay="200">
혁신적인 프로젝트와 창의적인 솔루션들을 만나보세요
<%- __('portfolio_page.subtitle') %>
</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">
전체
<%- __('portfolio_page.categories.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">
웹 개발
<%- __('portfolio_page.categories.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">
모바일 앱
<%- __('portfolio_page.categories.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 디자인
<%- __('portfolio_page.categories.ui-ux-design') %>
</button>
</div>
</div>
@@ -88,7 +90,7 @@
<% 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
<i class="fas fa-star"></i> <%- __('portfolio_page.labels.featured') %>
</span>
</div>
<% } %>
@@ -96,7 +98,7 @@
<!-- 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">
자세히 보기
<%- __('portfolio_page.buttons.details') %>
</a>
</div>
</div>
@@ -149,7 +151,7 @@
<!-- 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">
프로젝트 상세보기
<%- __('portfolio_page.buttons.projectDetails') %>
</a>
</div>
</div>
@@ -158,8 +160,8 @@
<% } 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>
<h3 class="text-2xl font-bold text-gray-500 mb-2"><%- __('portfolio_page.empty.title') %></h3>
<p class="text-gray-400"><%- __('portfolio_page.empty.subtitle') %></p>
</div>
<% } %>
</div>
@@ -168,7 +170,7 @@
<% 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">
더 많은 프로젝트 보기
<%- __('portfolio_page.buttons.loadMore') %>
</button>
</div>
<% } %>
@@ -179,17 +181,17 @@
<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">
다음 프로젝트의 주인공이 되어보세요
<%- __('portfolio_page.cta.title') %>
</h2>
<p class="text-xl mb-8 opacity-90" data-aos="fade-up" data-aos-delay="200">
우리와 함께 혁신적인 디지털 솔루션을 만들어보세요
<%- __('portfolio_page.cta.subtitle') %>
</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">
프로젝트 문의하기
<%- __('portfolio_page.buttons.contact') %>
</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">
비용 계산하기
<%- __('portfolio_page.buttons.calculate') %>
</a>
</div>
</div>
@@ -266,30 +268,30 @@
}
});
// Category name mapping
// Category name mapping - uses server-side localization
function getCategoryName(category) {
const categoryNames = {
'web-development': '웹 개발',
'mobile-app': '모바일 앱',
'ui-ux-design': 'UI/UX 디자인',
'branding': '브랜딩',
'marketing': '디지털 마케팅'
'web-development': '<%- __("portfolio_page.categories.web-development") %>',
'mobile-app': '<%- __("portfolio_page.categories.mobile-app") %>',
'ui-ux-design': '<%- __("portfolio_page.categories.ui-ux-design") %>',
'branding': '<%- __("portfolio_page.categories.branding") %>',
'marketing': '<%- __("portfolio_page.categories.marketing") %>'
};
return categoryNames[category] || category;
}
</script>
<%
// Helper function for category names
// Helper function for category names - uses i18n
function getCategoryName(category) {
const categoryNames = {
'web-development': '웹 개발',
'mobile-app': '모바일 앱',
'ui-ux-design': 'UI/UX 디자인',
'branding': '브랜딩',
'marketing': '디지털 마케팅'
const categoryMap = {
'web-development': 'portfolio_page.categories.web-development',
'mobile-app': 'portfolio_page.categories.mobile-app',
'ui-ux-design': 'portfolio_page.categories.ui-ux-design',
'branding': 'portfolio_page.categories.branding',
'marketing': 'portfolio_page.categories.marketing'
};
return categoryNames[category] || category;
return categoryMap[category] ? __(categoryMap[category]) : category;
}
%>
</body>