File: /var/www/indoadvisory_new/web/webapp/views/layouts/main.ejs
<!DOCTYPE html>
<html lang="<%= currentLang %>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%= title %></title>
<!-- SEO Meta Tags -->
<meta name="description" content="<%= locals.metaDescription || __('site_tagline') %>">
<meta name="keywords" content="private equity, Indonesia, investment, advisory, growth capital">
<meta name="author" content="Indo Advisory">
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="<%= title %>">
<meta property="og:description" content="<%= locals.metaDescription || __('site_tagline') %>">
<meta property="og:type" content="website">
<meta property="og:url" content="<%= locals.canonicalUrl || '' %>">
<meta property="og:site_name" content="<%= __('company_name') %>">
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- CSS Libraries -->
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css" rel="stylesheet">
<!-- Custom TailwindCSS Configuration -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
// McKinsey-inspired Professional Color Palette
mckinsey: {
navy: '#003366',
blue: '#0066CC',
lightblue: '#4D94FF',
gray: {
50: '#F8F9FA',
100: '#E9ECEF',
200: '#DEE2E6',
300: '#CED4DA',
400: '#ADB5BD',
500: '#6C757D',
600: '#495057',
700: '#343A40',
800: '#212529',
900: '#1A1D20'
}
},
primary: '#003366',
secondary: '#0066CC',
accent: '#4D94FF'
},
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
'serif': ['Playfair Display', 'Georgia', 'serif']
},
animation: {
'fade-in': 'fadeIn 0.6s ease-in-out',
'slide-up': 'slideUp 0.8s ease-out',
'scroll': 'scroll 20s linear infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' }
},
slideUp: {
'0%': { opacity: '0', transform: 'translateY(40px)' },
'100%': { opacity: '1', transform: 'translateY(0)' }
},
scroll: {
'0%': { transform: 'translateX(0)' },
'100%': { transform: 'translateX(-100%)' }
}
}
}
}
}
</script>
<!-- Custom CSS -->
<style>
/* McKinsey Professional Design System */
.mckinsey-gradient {
background: linear-gradient(135deg, #003366 0%, #0066CC 50%, #4D94FF 100%);
}
.mckinsey-gradient-subtle {
background: linear-gradient(135deg, #F8F9FA 0%, #E9ECEF 100%);
}
.mckinsey-card {
background: white;
border: 1px solid #DEE2E6;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 51, 102, 0.08);
transition: all 0.3s ease;
}
.mckinsey-card:hover {
box-shadow: 0 8px 25px rgba(0, 51, 102, 0.15);
transform: translateY(-2px);
}
.mckinsey-btn {
background: #003366;
color: white;
padding: 12px 24px;
border-radius: 6px;
font-weight: 600;
letter-spacing: 0.025em;
transition: all 0.3s ease;
border: 2px solid #003366;
}
.mckinsey-btn:hover {
background: #0066CC;
border-color: #0066CC;
transform: translateY(-1px);
}
.mckinsey-btn-outline {
background: transparent;
color: #003366;
border: 2px solid #003366;
padding: 12px 24px;
border-radius: 6px;
font-weight: 600;
letter-spacing: 0.025em;
transition: all 0.3s ease;
}
.mckinsey-btn-outline:hover {
background: #003366;
color: white;
transform: translateY(-1px);
}
.mckinsey-section {
padding: 80px 0;
}
.mckinsey-hero {
background: linear-gradient(135deg, #003366 0%, #0066CC 100%);
color: white;
padding: 120px 0;
}
.mckinsey-text {
color: #495057;
line-height: 1.7;
}
.mckinsey-heading {
color: #003366;
font-weight: 700;
line-height: 1.2;
}
.mckinsey-subheading {
color: #6C757D;
font-weight: 500;
line-height: 1.4;
}
/* Navigation Styles */
.nav-link {
color: #495057;
font-weight: 500;
transition: color 0.3s ease;
position: relative;
}
.nav-link:hover, .nav-link.active {
color: #003366;
}
.nav-link::after {
content: '';
position: absolute;
bottom: -6px;
left: 0;
width: 0;
height: 2px;
background: #0066CC;
transition: width 0.3s ease;
}
.nav-link:hover::after, .nav-link.active::after {
width: 100%;
}
/* Auto-scroll showcase */
.showcase-scroll {
animation: scroll 30s linear infinite;
}
.showcase-scroll:hover {
animation-play-state: paused;
}
/* Responsive utilities */
@media (max-width: 768px) {
.mckinsey-section {
padding: 60px 0;
}
.mckinsey-hero {
padding: 80px 0;
}
}
/* Loading animation */
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #003366;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<!-- Additional CSS from pages -->
<%- locals.additionalCSS || '' %>
</head>
<body class="font-sans antialiased bg-gray-50">
<!-- Skip Navigation -->
<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 bg-primary text-white px-4 py-2 rounded">
Skip to main content
</a>
<!-- Navigation -->
<nav class="bg-white shadow-sm border-b border-mckinsey-gray-200 sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<!-- Logo -->
<div class="flex-shrink-0">
<a href="/" class="flex items-center space-x-3">
<div class="w-10 h-10 mckinsey-gradient rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-lg">IA</span>
</div>
<span class="text-xl font-bold mckinsey-heading"><%= __('company_name') %></span>
</a>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:block">
<div class="ml-10 flex items-baseline space-x-8">
<a href="/" class="nav-link <%= locals.activePage === 'home' ? 'active' : '' %>">
<%= __('nav_home') %>
</a>
<a href="/about" class="nav-link <%= locals.activePage === 'about' ? 'active' : '' %>">
<%= __('nav_about') %>
</a>
<a href="/portfolio" class="nav-link <%= locals.activePage === 'portfolio' ? 'active' : '' %>">
<%= __('nav_portfolio') %>
</a>
<a href="/insights" class="nav-link <%= locals.activePage === 'insights' ? 'active' : '' %>">
<%= __('nav_insights') %>
</a>
<a href="/contact" class="nav-link <%= locals.activePage === 'contact' ? 'active' : '' %>">
<%= __('nav_contact') %>
</a>
<% if (isAdmin) { %>
<a href="/admin" class="nav-link text-mckinsey-blue">
<i class="fas fa-cog mr-1"></i>
<%= __('nav_admin') %>
</a>
<% } %>
</div>
</div>
<!-- Language Switcher & Mobile Menu -->
<div class="flex items-center space-x-4">
<!-- Language Switcher -->
<div class="relative">
<a href="/lang/<%= otherLang %>"
class="flex items-center space-x-2 px-3 py-2 rounded-md text-sm font-medium text-mckinsey-gray-600 hover:text-primary transition-colors"
title="<%= __('lang_switch') %>">
<i class="fas fa-globe"></i>
<span class="hidden sm:block"><%= otherLang.toUpperCase() %></span>
</a>
</div>
<!-- Mobile menu button -->
<div class="md:hidden">
<button type="button"
class="mobile-menu-button bg-mckinsey-gray-100 inline-flex items-center justify-center p-2 rounded-md text-mckinsey-gray-600 hover:text-primary hover:bg-mckinsey-gray-200 transition-colors"
aria-controls="mobile-menu"
aria-expanded="false">
<span class="sr-only">Open main menu</span>
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Mobile menu -->
<div class="md:hidden hidden" id="mobile-menu">
<div class="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-white border-t border-mckinsey-gray-200">
<a href="/" class="block px-3 py-2 nav-link <%= locals.activePage === 'home' ? 'active' : '' %>">
<%= __('nav_home') %>
</a>
<a href="/about" class="block px-3 py-2 nav-link <%= locals.activePage === 'about' ? 'active' : '' %>">
<%= __('nav_about') %>
</a>
<a href="/portfolio" class="block px-3 py-2 nav-link <%= locals.activePage === 'portfolio' ? 'active' : '' %>">
<%= __('nav_portfolio') %>
</a>
<a href="/insights" class="block px-3 py-2 nav-link <%= locals.activePage === 'insights' ? 'active' : '' %>">
<%= __('nav_insights') %>
</a>
<a href="/contact" class="block px-3 py-2 nav-link <%= locals.activePage === 'contact' ? 'active' : '' %>">
<%= __('nav_contact') %>
</a>
<% if (isAdmin) { %>
<a href="/admin" class="block px-3 py-2 nav-link text-mckinsey-blue">
<i class="fas fa-cog mr-1"></i>
<%= __('nav_admin') %>
</a>
<% } %>
</div>
</div>
</nav>
<!-- Flash Messages -->
<% if (messages.success && messages.success.length > 0) { %>
<div class="bg-green-50 border-l-4 border-green-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-check-circle text-green-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-green-700">
<%= messages.success[0] %>
</p>
</div>
</div>
</div>
<% } %>
<% if (messages.error && messages.error.length > 0) { %>
<div class="bg-red-50 border-l-4 border-red-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-triangle text-red-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
<%= messages.error[0] %>
</p>
</div>
</div>
</div>
<% } %>
<!-- Main Content -->
<main id="main-content">
<%- body %>
</main>
<!-- Footer -->
<footer class="bg-mckinsey-gray-900 text-white">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<!-- Company Info -->
<div class="col-span-1 md:col-span-2">
<div class="flex items-center space-x-3 mb-4">
<div class="w-10 h-10 mckinsey-gradient rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-lg">IA</span>
</div>
<span class="text-xl font-bold"><%= __('company_name') %></span>
</div>
<p class="text-mckinsey-gray-300 mb-4">
<%= __('site_tagline') %>
</p>
<div class="flex space-x-4">
<a href="#" class="text-mckinsey-gray-400 hover:text-white transition-colors">
<i class="fab fa-linkedin-in"></i>
</a>
<a href="#" class="text-mckinsey-gray-400 hover:text-white transition-colors">
<i class="fab fa-twitter"></i>
</a>
<a href="#" class="text-mckinsey-gray-400 hover:text-white transition-colors">
<i class="fas fa-envelope"></i>
</a>
</div>
</div>
<!-- Quick Links -->
<div>
<h4 class="font-semibold text-lg mb-4">Quick Links</h4>
<ul class="space-y-2">
<li><a href="/about" class="text-mckinsey-gray-300 hover:text-white transition-colors"><%= __('footer_about') %></a></li>
<li><a href="/portfolio" class="text-mckinsey-gray-300 hover:text-white transition-colors"><%= __('nav_portfolio') %></a></li>
<li><a href="/insights" class="text-mckinsey-gray-300 hover:text-white transition-colors"><%= __('nav_insights') %></a></li>
<li><a href="/contact" class="text-mckinsey-gray-300 hover:text-white transition-colors"><%= __('footer_contact') %></a></li>
</ul>
</div>
<!-- Contact Info -->
<div>
<h4 class="font-semibold text-lg mb-4">Contact</h4>
<div class="space-y-2 text-mckinsey-gray-300">
<p><i class="fas fa-envelope mr-2"></i> info@indoadvisory.com</p>
<p><i class="fas fa-phone mr-2"></i> +62 21 1234 5678</p>
<p><i class="fas fa-map-marker-alt mr-2"></i> Jakarta, Indonesia</p>
</div>
</div>
</div>
<div class="border-t border-mckinsey-gray-800 mt-8 pt-8 text-center text-mckinsey-gray-400">
<p><%= __('footer_copyright', { year: new Date().getFullYear() }) %></p>
</div>
</div>
</footer>
<!-- JavaScript Libraries -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
<!-- Custom JavaScript -->
<script>
// Mobile menu toggle
document.addEventListener('DOMContentLoaded', function() {
const mobileMenuButton = document.querySelector('.mobile-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
if (mobileMenuButton && mobileMenu) {
mobileMenuButton.addEventListener('click', function() {
mobileMenu.classList.toggle('hidden');
});
}
// Auto-hide flash messages
const flashMessages = document.querySelectorAll('[class*="bg-green-50"], [class*="bg-red-50"]');
flashMessages.forEach(message => {
setTimeout(() => {
message.style.transition = 'opacity 0.5s ease';
message.style.opacity = '0';
setTimeout(() => message.remove(), 500);
}, 5000);
});
// Smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth'
});
}
});
});
});
// Global utilities
window.IndoAdvisory = {
showLoading: function(element) {
if (element) {
element.innerHTML = '<span class="loading"></span> Loading...';
element.disabled = true;
}
},
hideLoading: function(element, originalText) {
if (element) {
element.innerHTML = originalText;
element.disabled = false;
}
},
showNotification: function(message, type = 'success') {
// Create notification element
const notification = document.createElement('div');
notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 ${
type === 'success' ? 'bg-green-500 text-white' : 'bg-red-500 text-white'
}`;
notification.innerHTML = `
<div class="flex items-center">
<i class="fas fa-${type === 'success' ? 'check' : 'exclamation-triangle'} mr-2"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(notification);
// Auto remove after 5 seconds
setTimeout(() => {
notification.style.transition = 'opacity 0.5s ease';
notification.style.opacity = '0';
setTimeout(() => notification.remove(), 500);
}, 5000);
}
};
</script>
<!-- Additional JavaScript from pages -->
<%- locals.additionalJS || '' %>
<!-- CSRF Token for AJAX requests -->
<% if (locals.csrfToken) { %>
<script>
// Set CSRF token for all AJAX requests
axios.defaults.headers.common['X-CSRF-Token'] = '<%= csrfToken %>';
</script>
<% } %>
</body>
</html>