diff --git a/.gitignore b/.gitignore index 4befed3..21943d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,41 @@ +# Node.js and npm/Yarn +node_modules/ +.pnp/ +.pnp.cjs +.yarn/ +.yarn-integrity + +# Build artifacts +dist/ +build/ +out/ +es/ +lib/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor/IDE specific files +.idea/ +.vscode/ +*.swp +*.swo .DS_Store -.idea +Thumbs.db + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Test coverage +coverage/ + +# Misc +*.tmp +*.bak diff --git a/2025/README.md b/2025/README.md new file mode 100644 index 0000000..0a2d07a --- /dev/null +++ b/2025/README.md @@ -0,0 +1,3 @@ +# Java Developers' Conference 2025 + +Never gonna give you up, never gonna let you down. diff --git a/2025/assets/css/schedule.css b/2025/assets/css/schedule.css new file mode 100644 index 0000000..f904f7f --- /dev/null +++ b/2025/assets/css/schedule.css @@ -0,0 +1,242 @@ +/* ============================================ + SCHEDULE PAGE - CLEAN TABULAR DESIGN + ============================================ */ + +/* Page Header */ +.page-header { + min-height: 40vh; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + position: relative; + padding: 120px 2rem 3rem; + background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.05)); +} + +.page-header-content { + max-width: 800px; + animation: fadeInUp 1s ease; +} + +.page-title { + font-size: clamp(2.5rem, 6vw, 3.5rem); + font-weight: 900; + margin: 1rem 0 0.5rem; + background: linear-gradient(135deg, var(--primary), var(--text-dim)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.page-subtitle { + color: var(--text-dim); + font-size: 1.1rem; + line-height: 1.6; +} + +/* Schedule Container */ +.schedule-page { + max-width: 1000px; + margin: 0 auto; + padding: 2rem 1.5rem 5rem; +} + +.schedule-container { + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 16px; + overflow: hidden; +} + +/* Table Styles */ +.schedule-table { + width: 100%; + border-collapse: collapse; +} + +.schedule-table th { + background: rgba(102, 126, 234, 0.1); + padding: 1rem 1.25rem; + text-align: left; + font-weight: 600; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-dim); + border-bottom: 1px solid var(--glass-border); +} + +.schedule-table td { + padding: 1rem 1.25rem; + border-bottom: 1px solid var(--glass-border); + vertical-align: middle; +} + +.schedule-table tbody tr:last-child td { + border-bottom: none; +} + +.schedule-table tbody tr:hover { + background: rgba(102, 126, 234, 0.05); +} + +/* Column Widths */ +.col-time { + width: 140px; + white-space: nowrap; + font-weight: 600; + color: var(--accent); +} + +.col-session { + color: var(--primary); +} + +.col-session a { + color: var(--primary); + text-decoration: none; + transition: color 0.2s ease; +} + +.col-session a:hover { + color: var(--accent); +} + +.col-speaker { + width: 200px; + color: var(--text-dim); +} + +/* Break Rows */ +.break-row { + background: rgba(255, 255, 255, 0.02); +} + +.break-row td { + color: var(--text-muted); + font-style: italic; +} + +.break-row .col-time { + color: var(--text-muted); +} + +.break-row:hover { + background: rgba(255, 255, 255, 0.04); +} + +/* Active nav link */ +.nav-links a.active::after { + content: ''; + position: absolute; + bottom: -5px; + left: 0; + width: 100%; + height: 2px; + background: var(--accent); +} + +/* Animation */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Responsive - Card layout on mobile */ +@media (max-width: 700px) { + .schedule-page { + padding: 1.5rem 1rem 4rem; + } + + .schedule-container { + background: transparent; + border: none; + border-radius: 0; + } + + .schedule-table, + .schedule-table thead, + .schedule-table tbody, + .schedule-table tr, + .schedule-table td { + display: block; + } + + .schedule-table thead { + display: none; + } + + .schedule-table tbody tr { + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 12px; + margin-bottom: 0.75rem; + padding: 1rem; + } + + .schedule-table td { + padding: 0.25rem 0; + border: none; + } + + .col-time { + width: auto; + font-size: 0.85rem; + margin-bottom: 0.5rem; + } + + .col-session { + font-weight: 600; + font-size: 1rem; + margin-bottom: 0.25rem; + } + + .col-speaker { + width: auto; + font-size: 0.9rem; + } + + .break-row { + background: rgba(255, 255, 255, 0.02); + border-style: dashed; + } + + .page-header { + min-height: 35vh; + padding: 100px 1.5rem 2rem; + } +} + +@media (max-width: 480px) { + .page-header { + padding: 80px 1rem 2rem; + } + + .page-title { + font-size: 2rem; + } +} + +/* Light theme */ +[data-theme="light"] .schedule-container { + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); +} + +[data-theme="light"] .schedule-table tbody tr:hover { + background: rgba(102, 126, 234, 0.08); +} + +[data-theme="light"] .break-row { + background: rgba(0, 0, 0, 0.02); +} + +[data-theme="light"] .break-row:hover { + background: rgba(0, 0, 0, 0.04); +} diff --git a/2025/assets/css/sessions.css b/2025/assets/css/sessions.css new file mode 100644 index 0000000..c3738d4 --- /dev/null +++ b/2025/assets/css/sessions.css @@ -0,0 +1,598 @@ +/* ============================================ + SESSIONS PAGE SPECIFIC STYLES + ============================================ */ + +/* Page Header */ +.page-header { + min-height: 60vh; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + position: relative; + padding: 120px 2rem 4rem; + background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.05)); +} + +.page-header-content { + max-width: 800px; + animation: fadeInUp 1s ease; +} + +.back-link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--text-dim); + text-decoration: none; + font-size: 0.95rem; + margin-bottom: 2rem; + padding: 10px 20px; + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 50px; + transition: all 0.3s ease; +} + +.back-link:hover { + background: rgba(102, 126, 234, 0.1); + border-color: var(--accent); + color: var(--primary); + transform: translateX(-5px); +} + +.page-title { + font-size: clamp(2.5rem, 6vw, 4rem); + font-weight: 900; + margin: 1rem 0; + background: linear-gradient(135deg, var(--primary), var(--text-dim)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.page-subtitle { + color: var(--text-dim); + font-size: 1.2rem; + line-height: 1.8; +} + +/* Sessions Page Container */ +.sessions-page { + max-width: 1400px; + min-width: 70%; + margin: 0 auto; + padding: 2rem 2rem 4rem; +} + +/* Filter Tabs */ +.session-filters { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; + margin-bottom: 3rem; + padding: 0 2rem; +} + +.filter-btn { + padding: 12px 24px; + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 50px; + color: var(--text-dim); + cursor: pointer; + transition: all 0.3s ease; + font-size: 0.95rem; + font-weight: 600; + font-family: inherit; +} + +.filter-btn:hover { + background: rgba(102, 126, 234, 0.1); + border-color: var(--accent); + color: var(--primary); + transform: translateY(-2px); +} + +.filter-btn.active { + background: var(--accent); + color: white; + border-color: var(--accent); + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); +} + +/* Sessions Grid */ +.sessions-grid { + display: grid; + gap: 2rem; + padding: 0 2rem; +} + +.sessions-grid h3 { + font-size: 1.5rem; + font-weight: 800; + margin-bottom: 2rem; +} + +.sessions-grid-content { + text-align: center; + padding: 4rem 0; +} + +.sessions-grid .section-title { + font-size: 2.5rem; + margin-bottom: 1rem; +} + +.sessions-grid .section-subtitle { + font-size: 1.15rem; + max-width: 600px; + margin: 0 auto 2rem auto; + color: var(--text-dim); + line-height: 1.8; +} + +.sessions-grid .btn-primary { + display: block; + margin: 2rem auto 0; + padding: 1rem 2.5rem; + font-size: 1.1rem; + font-weight: 600; + color: #fff; + background: linear-gradient(135deg, var(--accent), #ff6b6b); + border-radius: 50px; + text-decoration: none; + transition: all 0.3s ease; + box-shadow: 0 10px 30px rgba(255, 0, 64, 0.3); + max-width: 250px; + text-align: center; +} + +.sessions-grid .btn-primary:hover { + transform: translateY(-3px); + box-shadow: 0 20px 40px rgba(255, 0, 64, 0.4); +} + +.sessions-grid .section-background { + background: rgb(248, 242, 228); +} + +/* Session Card */ +.session-card { + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 24px; + overflow: hidden; + transition: all 0.4s ease; + position: relative; + animation: fadeInUp 0.6s ease forwards; + opacity: 0; +} + +.session-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: linear-gradient(90deg, var(--accent), var(--accent-hover)); + transform: scaleX(0); + transition: transform 0.4s ease; +} + +.session-card:hover::before { + transform: scaleX(1); +} + +.session-card:hover { + transform: translateY(-5px); + box-shadow: 0 20px 40px var(--shadow); + border-color: var(--accent); +} + +.session-content { + display: grid; + grid-template-columns: auto 1fr; + gap: 2rem; + align-items: start; + padding: 2rem; +} + +/* Time Badge */ +.session-time { + background: linear-gradient(135deg, var(--accent), var(--accent-hover)); + color: white; + padding: 1rem; + border-radius: 15px; + text-align: center; + min-width: 120px; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); +} + +.session-time .time { + font-size: 1.5rem; + font-weight: 800; + display: block; + margin-bottom: 0.3rem; +} + +.session-time .duration { + font-size: 0.85rem; + opacity: 0.9; +} + +/* Session Info */ +.session-info { + flex: 1; +} + +.session-category { + display: inline-block; + padding: 6px 14px; + background: rgba(102, 126, 234, 0.15); + color: var(--accent); + border-radius: 20px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 1rem; +} + +.session-title { + font-size: 1.8rem; + font-weight: 700; + color: var(--primary); + margin-bottom: 1rem; + line-height: 1.3; +} + +.session-abstract { + color: var(--text-dim); + line-height: 1.8; + margin-bottom: 0.5rem; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 5; /* show 5 lines by default */ + overflow: hidden; +} + +/* Expanded state shows full abstract */ +.session-card.expanded .session-abstract { + display: block; + -webkit-line-clamp: initial; + overflow: visible; + /* Keep the same measure as collapsed state to avoid line-length shift */ +} + +/* Ensure minimal line gap between paragraphs inside session abstracts */ +.session-abstract p { + margin: 0 0 0.4rem; /* minimal bottom gap */ +} +.session-abstract p:last-child { + margin-bottom: 0; /* no extra space after the last paragraph */ +} + +.read-more { + background: transparent; + border: none; + color: var(--accent); + font: inherit; + font-weight: 600; + cursor: pointer; + display: inline-flex; + padding: 0; + margin: 0.25rem 0 1.25rem 0; + user-select: none; + text-decoration: none; + white-space: nowrap; /* keep inline text on a single line */ + line-height: 1.8; +} + + +.read-more:hover, +.read-more:focus { + text-decoration: underline; +} + +.read-more::after { + content: ' →'; +} + +.session-card.expanded .read-more::after { + content: ' ↑'; +} + + +/* Speaker Info */ +.session-speaker { + display: flex; + align-items: center; + gap: 1rem; + padding-top: 1.5rem; + border-top: 1px solid var(--glass-border); + margin-top: 1.5rem; + cursor: pointer; /* Make it clear it's clickable */ + user-select: none; + transition: transform 0.2s ease; +} + +/* Larger avatar size for better visibility on Sessions page */ +.speaker-avatar { + width: 80px; + height: 80px; + border-radius: 50%; + object-fit: cover; + border: 3px solid var(--accent); + box-shadow: 0 6px 16px rgba(102, 126, 234, 0.35); + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; +} + +/* Explicit large variant if used elsewhere */ +.speaker-avatar-large { + width: 88px; + height: 88px; +} + +/* Hover and focus effects to encourage clicking for bio */ +.session-speaker:hover .speaker-avatar, +.session-speaker:focus-visible .speaker-avatar { + transform: scale(1.06); + box-shadow: 0 10px 24px rgba(102, 126, 234, 0.5); + border-color: #8ea2ff; +} + +.session-speaker:focus-visible { + outline: 3px solid rgba(102, 126, 234, 0.5); + outline-offset: 4px; + border-radius: 14px; +} + +.speaker-details { + flex: 1; +} + +.speaker-name { + font-size: 1.1rem; + font-weight: 700; + color: var(--primary); + margin-bottom: 0.3rem; +} + +.speaker-role { + font-size: 0.9rem; + color: var(--text-muted); +} + +.session-tags { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + margin-top: 1rem; +} + +.tag { + padding: 6px 12px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid var(--glass-border); + border-radius: 15px; + font-size: 0.8rem; + color: var(--text-dim); + transition: all 0.3s ease; +} + +.tag:hover { + background: rgba(102, 126, 234, 0.1); + border-color: var(--accent); + color: var(--accent); +} + +/* Track Colors */ +.session-card[data-track="keynote"] .session-time { + background: linear-gradient(135deg, #f093fb, #f5576c); +} + +.session-card[data-track="keynote"] .session-category { + background: rgba(240, 147, 251, 0.15); + color: #f093fb; +} + +.session-card[data-track="technical"] .session-time { + background: linear-gradient(135deg, #667eea, #764ba2); +} + +.session-card[data-track="workshop"] .session-time { + background: linear-gradient(135deg, #4facfe, #00f2fe); +} + +.session-card[data-track="workshop"] .session-category { + background: rgba(79, 172, 254, 0.15); + color: #4facfe; +} + +.session-card[data-track="panel"] .session-time { + background: linear-gradient(135deg, #43e97b, #38f9d7); +} + +.session-card[data-track="panel"] .session-category { + background: rgba(67, 233, 123, 0.15); + color: #43e97b; +} + +/* Empty State */ +.empty-state { + text-align: center; + padding: 4rem 2rem; + color: var(--text-dim); +} + +.empty-state-icon { + font-size: 4rem; + margin-bottom: 1rem; + opacity: 0.5; +} + +.empty-state h3 { + font-size: 1.5rem; + margin-bottom: 0.5rem; + color: var(--primary); +} + +.empty-state p { + color: var(--text-muted); +} + +/* Animation */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.nav-links a.active::after { + content: ''; + position: absolute; + bottom: -5px; + left: 0; + width: 100%; + height: 2px; + background: var(--accent); +} + +/* Responsive Styles */ +@media (max-width: 968px) { + .session-content { + grid-template-columns: 1fr; + } + + .session-time { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.5rem; + } + + .session-time .time, + .session-time .duration { + display: inline; + } + + .page-header { + min-height: 50vh; + padding: 100px 2rem 3rem; + } +} + +@media (max-width: 768px) { + .sessions-page { + padding: 2rem 0 4rem; + } + + .sessions-grid { + padding: 0 1rem; + } + + .session-filters { + padding: 0 1rem; + } + + .session-title { + font-size: 1.5rem; + } + + .session-speaker { + flex-direction: column; + align-items: flex-start; + } + + .filter-btn { + padding: 10px 18px; + font-size: 0.85rem; + } + + .page-header { + padding: 80px 1rem 2rem; + } + + .page-title { + font-size: 2rem; + } + + .page-subtitle { + font-size: 1rem; + } +} + +@media (max-width: 480px) { + .session-card { + border-radius: 16px; + } + + .session-content { + padding: 1.5rem; + } + + .session-time { + min-width: auto; + border-radius: 12px; + } + + .session-time .time { + font-size: 1.2rem; + } + + .session-title { + font-size: 1.3rem; + } + + .speaker-avatar { + width: 50px; + height: 50px; + } + + .session-filters { + gap: 0.5rem; + } +} + +/* ============================================ + COMING SOON CARD (Sessions page) - alignment fix + ============================================ */ +.session-card.coming-soon { + cursor: default; +} +.session-card.coming-soon .session-content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 2rem; +} +.session-card.coming-soon .session-info { + max-width: 720px; +} +.session-card.coming-soon .session-category { + margin-left: auto; + margin-right: auto; +} + +[data-theme="dark"] .sessions-grid .section-background { + background: #2c2c2c; +} + + +/* Background fade removed as requested */ +.session-abstract::after { + content: none; + display: none; +} + diff --git a/2025/assets/css/styles.css b/2025/assets/css/styles.css new file mode 100644 index 0000000..eeaae1a --- /dev/null +++ b/2025/assets/css/styles.css @@ -0,0 +1,2182 @@ +@import url('https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap'); + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --primary: #ffffff; + --accent: #ff0040; + --accent-glow: #ff0040; + --bg-dark: #2d2d30; /* Much lighter from #0a0a0a */ + --bg-darker: #252526; /* Much lighter from #000000 */ + --glass: rgba(255, 255, 255, 0.15); /* Much more visible */ + --glass-border: rgba(255, 255, 255, 0.25); /* Much more visible */ + --text-dim: rgba(255, 255, 255, 0.85); + --text-muted: rgba(255, 255, 255, 0.65); + --gradient-1: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --gradient-2: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + --transition-speed: 0.4s; /* Added for smooth theme transition */ + + --speaker-image-size: 240px; +} + +/* Light Mode Colors */ +[data-theme="light"] { + --primary: #1a1a1a; + --secondary: #2d2d2d; + --accent: #667eea; + --accent-hover: #5568d3; + --accent-glow: rgba(102, 126, 234, 0.2); + --bg-dark: #ffffff; + --bg-darker: #f8f9fa; + --bg-darkest: #f0f1f3; + --glass: rgba(0, 0, 0, 0.05); + --glass-border: rgba(0, 0, 0, 0.1); + --text-dim: rgba(0, 0, 0, 0.8); + --text-muted: rgba(0, 0, 0, 0.6); + --shadow: rgba(0, 0, 0, 0.1); + --card-bg: rgba(0, 0, 0, 0.02); +} + +/* Apply transitions to all theme-dependent properties */ +body, +nav, +.hero, +.about, +.speakers, +.countdown, +.venue, +footer, +.card, +.speaker-card, +.why-card, +.timer-block, +.address-card, +.venue-map, +.speaker-modal, +.modern-carousel-container { + transition: background var(--transition-speed) ease, + color var(--transition-speed) ease, + border-color var(--transition-speed) ease, + box-shadow var(--transition-speed) ease; +} + +/* Theme Toggle Button Styles */ +.theme-toggle { + position: relative; + width: 60px; + height: 30px; + background: var(--glass); + border: 2px solid var(--glass-border); + border-radius: 50px; + cursor: pointer; + transition: all var(--transition-speed) ease; + display: flex; + align-items: center; + padding: 0 4px; +} + +.theme-toggle:hover { + border-color: var(--accent); + transform: scale(1.05); +} + +.theme-toggle-slider { + width: 20px; + height: 20px; + background: var(--accent); + border-radius: 50%; + transition: transform var(--transition-speed) cubic-bezier(0.68, -0.55, 0.265, 1.55); + display: flex; + align-items: center; + justify-content: center; + font-size: 0.7rem; + box-shadow: 0 2px 8px var(--accent-glow); +} + +[data-theme="light"] .theme-toggle-slider { + transform: translateX(28px); +} + +/* Light mode specific adjustments */ +[data-theme="light"] .bg-animation { + background: radial-gradient(ellipse at top, #e0e7ff 0%, #f0f1f3 100%); +} + +[data-theme="light"] .glow-orb { + opacity: 0.2; +} + +[data-theme="light"] .scroll-indicator::before { + background: transparent; +} + +[data-theme="light"] .scroll-indicator::after { + border-color: var(--text-dim); + background: var(--text-dim); +} + +[data-theme="light"] .hero-title { + background: linear-gradient(135deg, #1a1a1a, #2d2d2d); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +[data-theme="light"] .cta-button { + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); +} + +[data-theme="light"] .speaker-image, +[data-theme="light"] .modern-carousel-image { + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); +} + +[data-theme="light"] .speaker-modal-overlay { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10px); +} + +[data-theme="light"] .timer-block:hover { + background: rgba(102, 126, 234, 0.05); +} + +/* Improve text contrast in light mode */ +[data-theme="light"] .about-description, +[data-theme="light"] .speaker-bio, +[data-theme="light"] .card-description, +[data-theme="light"] .why-card-body { + color: var(--text-dim); +} + +body { + font-family: Ubuntu, sans-serif; + background: var(--bg-dark); + color: var(--primary); + overflow-x: hidden; + cursor: default; + display: flex; + flex-direction: column; + min-height: 100vh; + align-items: center; +} + +a { + color: var(--primary); + text-decoration: none; + text-decoration-skip-ink: none; + background-image: linear-gradient(currentColor, currentColor); + background-position: 0 100%; + background-repeat: no-repeat; + background-size: 100% 1px; + transition: background-size 0.3s ease, color 0.3s ease; +} + +a:hover, +a:focus { + color: var(--primary); + background-size: 100% 2px; +} + + +/* Animated Background */ +.bg-animation { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: -1; + background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%); + overflow: hidden; +} + +.glow-orb { + position: absolute; + width: 600px; + height: 600px; + border-radius: 50%; + filter: blur(80px); + opacity: 0.4; + animation: float 20s infinite ease-in-out; +} + +@media screen and (max-width: 600px) { + .glow-orb { + width: 100%; + height: 100%; + } +} + +.orb1 { + background: linear-gradient(135deg, #667eea, #764ba2); + top: -300px; + left: -300px; + animation-delay: 0s; +} + +.orb2 { + background: linear-gradient(135deg, #f093fb, #f5576c); + bottom: -300px; + right: -300px; + animation-delay: 10s; +} + +@keyframes float { + 0%, 100% { + transform: translate(0, 0) scale(1); + } + 33% { + transform: translate(100px, -100px) scale(1.1); + } + 66% { + transform: translate(-100px, 100px) scale(0.9); + } +} + +.fade-in-section { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.fade-in-section.visible { + opacity: 1; + transform: translateY(0); +} + +/* Navigation */ +nav { + position: fixed; + top: 0; + width: 100%; + padding: 20px 0px; + z-index: 1000; + backdrop-filter: blur(20px); + background: linear-gradient(to bottom, rgba(196, 201, 255, 0.7), transparent); + transition: all 0.3s ease; +} + +[data-theme="dark"] nav { + background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7), transparent); +} + +nav.scrolled { + background: rgba(255, 255, 255, 0.2); /* More transparent for glass effect */ + backdrop-filter: blur(20px); + padding: 5px 0; + transition: all 0.3s ease; + border-bottom: 1px solid rgba(255, 255, 255, 0.3); +} + +.nav-content { + display: flex; + justify-content: space-between; + align-items: center; + max-width: 1400px; + margin: 0 auto; + padding: 0 50px; +} + +.logo { + background: linear-gradient(135deg, var(--accent), #ff6b6b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + letter-spacing: -1px; + position: relative; + filter: drop-shadow(5px 5px 10px #ff6b6b); + + img { + width: 80px; + height: 50px; + margin: 0; + padding: 0; + } +} + +.logo::after { + display: none; +} + +.nav-links { + display: flex; + gap: 40px; + list-style: none; + align-items: center; +} + +.nav-links a { + color: var(--text-dim); + text-decoration: none; + font-size: 0.95rem; + transition: all 0.3s ease; + position: relative; + padding: 5px 0; + background-image: none; +} + +.nav-links a::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 0; + height: 2px; + background: var(--accent); + transition: width 0.3s ease; +} + +.nav-links a:hover { + color: var(--primary); +} + +.nav-links a:hover::after { + width: 100%; +} + +.menu-toggle { + display: none; + flex-direction: column; + gap: 6px; + cursor: pointer; +} + +.menu-toggle span { + width: 30px; + height: 2px; + background: var(--primary); + transition: all 0.3s ease; +} + +/* Hero Section */ +.hero { + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: relative; + overflow: hidden; +} + +.hero-content { + text-align: center; + z-index: 10; + animation: fadeInUp 1s ease; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.hero-title { + font-size: clamp(3rem, 8vw, 4.5rem); + font-weight: 900; + line-height: 1.5; + margin-bottom: 20px; + background: linear-gradient(135deg, #fff, var(--text-dim)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + letter-spacing: -3px; +} + +.hero-subtitle { + font-size: 2rem; + color: var(--text-dim); + margin-bottom: 40px; + font-weight: bold; +} + +.cta-button { + display: inline-block; + padding: 18px 50px; + background: linear-gradient(135deg, var(--accent), #ff6b6b); + color: white; + text-decoration: none; + border-radius: 50px; + font-weight: 600; + font-size: 1.1rem; + transition: all 0.3s ease; + position: relative; + overflow: hidden; + box-shadow: 0 10px 30px rgba(255, 0, 64, 0.3); +} + +.cta-button::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transition: left 0.5s ease; +} + +.cta-button:hover::before { + left: 100%; +} + +.cta-button:hover { + transform: translateY(-3px); + box-shadow: 0 20px 40px rgba(255, 0, 64, 0.4); +} + +/* Scroll Indicator */ +.scroll-indicator { + position: absolute; + bottom: 30px; + left: 50%; + transform: translateX(-50%); + animation: bounce 2s infinite; +} + +.scroll-indicator { + opacity: 1; + transition: opacity 0.5s ease; +} + +.scroll-indicator.hide { + opacity: 0; + pointer-events: none; +} + +@keyframes bounce { + 0%, 100% { + transform: translateX(-50%) translateY(0); + } + 50% { + transform: translateX(-50%) translateY(-10px); + } +} + +.scroll-indicator::before { + content: ''; + display: block; + width: 30px; + height: 50px; + border: 2px solid var(--text-dim); + border-radius: 25px; + position: relative; +} + +.scroll-indicator::after { + content: ''; + display: block; + width: 4px; + height: 10px; + background: var(--text-dim); + border-radius: 2px; + position: absolute; + top: 10px; + left: 50%; + transform: translateX(-50%); + animation: scroll-dot 2s infinite; +} + +@keyframes scroll-dot { + 0%, 100% { + top: 10px; + opacity: 1; + } + 50% { + top: 25px; + opacity: 0.3; + } +} + +section { + padding: 5rem 1rem; +} + +.hero, +.about, +.sponsors, +.session-preview, +#why-jdc { + max-width: 1200px; +} + +.speakers, +#our-team { + max-width: 1400px; +} + +/* About Section */ +.about { + margin: 0 auto; + display: flex; + width: 100%; +} + +.about-content { + display: flex; + gap: 80px; + align-items: center; + max-width: 45rem; +} + +.about-text { + animation: fadeInLeft 1s ease; +} + +@keyframes fadeInLeft { + from { + opacity: 0; + transform: translateX(-30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.section-tag { + display: inline-block; + padding: 8px 20px; + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 50px; + font-size: 0.85rem; + color: var(--accent); + margin-bottom: 20px; + backdrop-filter: blur(10px); +} + +.section-subtitle { + font-size: 2rem; + font-weight: 700; + margin: 2rem 0 1rem; + color: var(--text-muted) +} + +.section-title { + font-size: 3rem; + font-weight: 800; + margin-bottom: 30px; + line-height: 1.2; +} + +.gradient-text { + background: linear-gradient(135deg, var(--primary), var(--text-dim)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.about-description { + font-size: 1.15rem; + line-height: 1.8; + color: var(--text-dim); +} +.about-description p { + margin-bottom: 1rem; +} + +/* Gallery Section */ +#gallery { + position: relative; + text-align: center; + width: 90rem; +} + +@media screen and (max-width: 90rem) { + #gallery { + width: 100%; + } +} + +.gallery-header { + margin-bottom: 4rem; +} + +.image-carousel-container { + max-width: 1200px; + margin: 0 auto; + position: relative; + border-radius: 20px; + overflow: hidden; + background: var(--glass); + border: 1px solid var(--glass-border); + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3); +} + +.carousel-track-container { + overflow: hidden; +} + +.carousel-track { + position: relative; + list-style: none; + padding: 0; + margin: 0; + display: flex; + transition: transform 0.5s ease-in-out; +} + +.carousel-slide { + position: absolute; + top: 0; + width: 100%; + height: 100%; + opacity: 0; + transition: opacity 0.5s ease-in-out; +} + +.carousel-slide.active { + opacity: 1; + position: relative; +} + +.carousel-slide img { + width: 100%; + height: 600px; + object-fit: cover; + display: block; +} + +.carousel-nav { + position: absolute; + top: 50%; + width: 100%; + display: flex; + justify-content: space-between; + transform: translateY(-50%); + pointer-events: none; + padding: 0 20px; +} + +.carousel-button { + pointer-events: all; + background: var(--glass); + border: 1px solid var(--glass-border); + color: var(--primary); + border-radius: 50%; + width: 50px; + height: 50px; + font-size: 1.5rem; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.carousel-button:hover { + background: var(--accent); + border-color: var(--accent); + transform: scale(1.1); +} + +.carousel-indicators { + position: absolute; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + display: flex; + gap: 10px; +} + +.carousel-indicator { + width: 12px; + height: 12px; + border-radius: 50%; + background: var(--glass-border); + border: none; + cursor: pointer; + transition: all 0.3s ease; +} + +.carousel-indicator.active { + background: var(--accent); + transform: scale(1.2); +} + + +/* Speakers Section */ +.speakers { + margin: 0 auto; +} + +.speakers-header { + text-align: center; + margin-bottom: 80px; +} + +.speakers-grid { + display: flex; + flex-wrap: wrap; + gap: 2rem; + justify-content: center; +} + +.speakers-grid > .speaker-card { + flex: 0 0 var(--speaker-image-size); +} + +.speaker-card { + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 20px; + overflow: hidden; + transition: all 0.3s ease; + cursor: pointer; + position: relative; + width: var(--speaker-image-size); +} + +.speaker-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, var(--accent), #ff6b6b); + transform: scaleX(0); + transition: transform 0.3s ease; +} + +.speaker-card:hover::before { + transform: scaleX(1); +} + +.speaker-card:hover { + transform: translateY(-10px); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); +} + +.speaker-image { + width: 100%; + aspect-ratio: 1/1; + object-fit: cover; + transition: transform 0.3s ease; +} + +.speaker-card:hover .speaker-image { + transform: scale(1.05); +} + +.speaker-info { + padding: 1rem; + text-align: center; +} + +.speaker-name { + font-size: 1.2rem; + font-weight: 700; + margin-bottom: 10px; +} + +.speaker-company { + color: var(--text-dim); + font-size: 0.95rem; +} + +.speaker-bio { + font-size: 0.9rem; + line-height: 1.6; + color: var(--text-dim); +} + +/* Speaker Modal Styles */ +.speaker-modal-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + backdrop-filter: blur(10px); + z-index: 9999; + animation: fadeIn 0.3s ease; +} + +.speaker-modal-overlay.active { + display: flex; + justify-content: center; + align-items: center; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.speaker-modal { + background: var(--bg-darker); + border: 1px solid var(--glass-border); + border-radius: 24px; + max-width: 800px; + width: 90%; + max-height: 85vh; + overflow-y: auto; + position: relative; + animation: slideUp 0.3s ease; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); + + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + + ::-webkit-scrollbar { + display: none; /* Chrome, Safari, Opera */ + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(30px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.speaker-modal-close { + position: absolute; + top: 20px; + right: 20px; + width: 40px; + height: 40px; + background: transparent; + border: none; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.3s ease; + z-index: 10; +} + +.speaker-modal-close:hover { + background: var(--accent); + transform: rotate(90deg); +} + +.speaker-modal-close::before, +.speaker-modal-close::after { + content: ''; + position: absolute; + width: 20px; + height: 2px; + background: var(--primary); +} + +.speaker-modal-close:hover::before, +.speaker-modal-close:hover::after { + background: #ffffff; +} + +.speaker-modal-close::before { + transform: rotate(45deg); +} + +.speaker-modal-close::after { + transform: rotate(-45deg); +} + +.speaker-modal-content { + padding: 40px; +} + +.speaker-modal-header { + display: flex; + gap: 30px; + align-items: center; + margin-bottom: 30px; + padding-bottom: 30px; + border-bottom: 1px solid var(--glass-border); +} + +.speaker-modal-image { + width: 150px; + height: 150px; + border-radius: 20px; + object-fit: cover; + /* --- CHANGE APPLIED HERE --- */ + border: 1px solid var(--glass-border); + box-shadow: 0 10px 30px rgba(255, 0, 64, 0.2); +} + +.speaker-modal-info { + flex: 1; +} + +.speaker-modal-name { + font-size: 2rem; + font-weight: 800; + background: linear-gradient(135deg, var(--primary), var(--text-dim)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-bottom: 10px; +} + +.speaker-modal-title { + font-size: 1.1rem; + color: var(--accent); + margin-bottom: 8px; +} + +.speaker-modal-company { + font-size: 1rem; + color: var(--text-dim); +} + +.speaker-modal-bio { + margin-bottom: 30px; +} + +.speaker-modal-bio h3 { + font-size: 1.3rem; + color: var(--primary); + margin-bottom: 15px; + display: flex; + align-items: center; + gap: 10px; +} + +.speaker-modal-bio h3::before { + content: ''; + width: 30px; + height: 3px; + background: var(--accent); +} + +.speaker-modal-bio p { + font-size: 1.05rem; + line-height: 1.8; + color: var(--text-dim); +} + +.speaker-detail-item { + background: var(--glass); + padding: 20px; + border-radius: 12px; + border: 1px solid var(--glass-border); +} + +.speaker-detail-label { + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 1px; + color: var(--accent); + margin-bottom: 8px; +} + +.speaker-detail-value { + font-size: 1rem; + color: var(--primary); +} + +/* Scrollbar styling for modal */ +.speaker-modal::-webkit-scrollbar { + width: 8px; +} + +.speaker-modal::-webkit-scrollbar-track { + background: var(--glass); + border-radius: 4px; +} + +/* --- CHANGES APPLIED HERE --- */ +.speaker-modal::-webkit-scrollbar-thumb { + background: var(--text-dim); + border-radius: 4px; +} + +.speaker-modal::-webkit-scrollbar-thumb:hover { + background: var(--primary); +} + +/* Prevent body scroll when modal is open */ +body.modal-open { + overflow: hidden; +} + +@media screen and (max-width: 650px) { + .speakers-grid { + gap: 1rem; + } + + .speakers-grid > .speaker-card { + flex: 1 1 150px; + } + + .speaker-card { + max-width: 180px; + } + + .speaker-name { + font-size: 1rem; + } + + .speaker-company { + font-size: 0.85rem; + } +} + +/* Why JDC Section - Card Layout */ +#why-jdc { + margin: 0 auto; + text-align: left; +} + +#why-jdc .section-title.gradient-text { + position: relative; + padding-bottom: 1rem; + margin-bottom: 3rem; + background: none; + -webkit-text-fill-color: unset; + color: #fff; +} + +#why-jdc .section-title.gradient-text::after { + content: ''; + position: absolute; + left: 0; + bottom: 0; + width: 60px; + height: 4px; + background-color: #CF0060; + border-radius: 2px; +} + +.why-grid { + display: flex; + flex-wrap: wrap; + gap: 2rem; +} + +.why-card { + background: rgba(108, 118, 180, 0.55); + backdrop-filter: blur(10px); + border-radius: 15px; + padding: 2.5rem 1.5rem; + border: 1px solid rgba(255, 255, 255, 0.1); + transition: transform 0.4s ease, box-shadow 0.4s ease; + z-index: 1; + flex-grow: 1; + flex-basis: 0; + min-width: 300px; + min-height: 150px; +} + +.why-card:hover { + transform: translateY(-10px) scale(1.03); + box-shadow: 0 25px 50px rgba(0, 0, 0, 0.4); +} + +.why-card:hover::before { + opacity: 1; +} + +.why-card-title { + font-size: 1.5rem; + color: #fff; + margin-top: 0; + margin-bottom: 1rem; +} + +.why-card-body { + font-size: 1rem; + color: #e7ecff; + line-height: 1.6; + margin: 0; +} + +/* Countdown Section */ +.countdown { + text-align: center; + background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1)); + position: relative; + overflow: hidden; + width: 100%; +} + +.countdown::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 150%; + height: 150%; + background: radial-gradient(circle, rgba(255, 0, 64, 0.1) 0%, transparent 70%); + animation: rotate 30s linear infinite; +} + +@keyframes rotate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.countdown-content { + position: relative; + z-index: 10; +} + +.countdown-title { + font-size: 3rem; + font-weight: 800; + margin-bottom: 60px; +} + +.timer-container { + display: flex; + flex-wrap: wrap; + gap: 20px; + max-width: 800px; + margin: 0 auto 60px; +} + +.timer-block { + background: var(--glass); + border: 1px solid var(--glass-border); + padding: 30px 20px; + border-radius: 20px; + backdrop-filter: blur(10px); + transition: all 0.3s ease; + flex-grow: 1; + flex-basis: 0; + min-width: 150px; + text-align: center; +} + +.timer-block:hover { + transform: scale(1.03); + background: rgba(255, 0, 64, 0.1); + border-color: var(--accent); +} + +.timer-number { + font-size: 4rem; + font-weight: 800; + background: linear-gradient(135deg, var(--accent), #ff6b6b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + display: block; + line-height: 1; +} + +.timer-label { + font-size: 0.9rem; + color: var(--text-dim); + text-transform: uppercase; + letter-spacing: 2px; + margin-top: 10px; +} + +.event-date { + font-size: 2rem; + color: var(--text-dim); + margin-bottom: 40px; +} + +/* Venue Section */ +.venue { + margin: 5rem auto 0 auto; +} + +.venue-content { + display: flex; + gap: 80px; + align-items: center; + justify-content: center; + flex-wrap: wrap; + width: 90vw; +} + +.venue-info, +.venue-map { + flex-grow: 1; + flex-basis: 0; + max-width: 40%; +} + +.venue-info { + order: 2; +} + +.venue-map { + order: 1; + position: relative; + border-radius: 20px; + overflow: hidden; + height: 515px; + background: var(--glass); + border: 1px solid var(--glass-border); +} + +.venue-map iframe { + width: 100%; + height: 100%; +} + +.venue-info .about-description { + background: var(--glass); + padding: 20px; + border-radius: 15px; + border: 1px solid var(--glass-border); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); +} + +.address-card { + background: var(--glass); + border: 1px solid var(--glass-border); + padding: 30px; + border-radius: 20px; + margin-top: 30px; + backdrop-filter: blur(10px); +} + +.address-card h3 { + font-size: 1.3rem; + margin-bottom: 20px; + color: var(--accent); +} + +.address-card p { + color: var(--text-dim); + line-height: 1.8; + margin-bottom: 10px; +} + +/* Our Team Section */ +#our-team { + margin: 0 auto; + position: relative; + text-align: center; +} + +.our-team-title { + font-size: 2.8rem; + font-weight: 800; + margin-bottom: 18px; + background: linear-gradient(135deg, var(--accent), var(--primary) 80%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + letter-spacing: -1px; +} + +.our-team-subtitle { + color: var(--text-dim); + font-size: 1.2rem; + margin-bottom: 48px; + font-weight: 500; +} + +.team-grid { + /* Switched from CSS Grid to Flexbox to center-align the last row */ + display: flex; + flex-wrap: wrap; + gap: 40px; + justify-content: center; /* Ensures the last row is centered */ + /*align-items: stretch;*/ +} + +/* Ensure consistent responsive sizing for team cards inside flex container */ +.team-grid > .team-card { + flex: 1 1 220px; /* target ~220px width, allow wrapping */ + max-width: 360px; /* prevent cards from stretching too wide on large screens */ +} + +.team-card { + background: var(--glass); + border: 1.5px solid var(--glass-border); + border-radius: 18px; + box-shadow: 0 4px 24px 0 rgba(0, 0, 0, 0.10); + padding: 36px 18px 28px 18px; + display: flex; + flex-direction: column; + align-items: center; + transition: transform 0.18s, box-shadow 0.18s; + position: relative; + overflow: hidden; +} + +.team-card:hover { + transform: translateY(-6px) scale(1.03); + box-shadow: 0 8px 32px 0 rgba(255, 0, 64, 0.10); +} + +.team-img { + width: 96px; + height: 96px; + object-fit: cover; + border-radius: 50%; + border: 3px solid var(--accent); + margin-bottom: 18px; + background: var(--bg-darker); + box-shadow: 0 5px 20px rgba(0, 0, 0, 0.25); +} + +.team-name { + font-size: 1.18rem; + font-weight: 700; + color: var(--primary); + margin-bottom: 4px; +} + +.team-role { + font-size: 1rem; + color: var(--accent); + font-weight: 500; + margin-bottom: 0; +} + +.team-socials { + margin-top: 14px; + display: flex; + gap: 14px; +} + +.team-socials a { + color: var(--accent); + font-size: 1.2rem; + transition: color 0.2s; + background-image: none; +} + +.team-socials a:hover { + color: var(--primary); +} + +@media (max-width: 700px) { + #our-team { + padding: 60px 16px 40px 16px; + } + + .team-grid { + gap: 24px; + } + + .our-team-title { + font-size: 2rem; + } +} + +/* ============================================ + SESSION PREVIEW SECTION (For main page) + ============================================ */ + +#session { + margin: 0 auto; + position: relative; + width: 100%; +} +#session h3 { + font-size: 1.5rem; + font-weight: 800; + margin-bottom: 2rem; +} + +.session-preview-content { + text-align: center; + padding: 4rem 0; +} + +.session-preview .section-title { + font-size: 2.5rem; + margin-bottom: 1rem; +} + +.session-preview .section-subtitle { + font-size: 1.15rem; + max-width: 600px; + margin: 0 auto 2rem auto; + color: var(--text-dim); + line-height: 1.8; +} + +.session-preview .btn-primary { + display: block; + margin: 2rem auto 0; + padding: 1rem 2.5rem; + font-size: 1.1rem; + font-weight: 600; + color: #fff; + background: linear-gradient(135deg, var(--accent), #ff6b6b); + border-radius: 50px; + text-decoration: none; + transition: all 0.3s ease; + box-shadow: 0 10px 30px rgba(255, 0, 64, 0.3); + max-width: 250px; + text-align: center; +} + +.session-preview .btn-primary:hover { + transform: translateY(-3px); + box-shadow: 0 20px 40px rgba(255, 0, 64, 0.4); +} + +.session-preview .section-background { + background: rgb(248, 242, 228); +} + +.session-preview-header { + text-align: center; + margin-bottom: 4rem; +} + +.section-description { + color: var(--text-dim); + font-size: 1.15rem; + max-width: 700px; + margin: 1rem auto 0; + line-height: 1.8; +} + +/* See more button inside session preview header */ +.see-more-btn { + display: inline-block; + margin-top: 1rem; + padding: 10px 18px; + border: 1px solid var(--glass-border); + border-radius: 999px; + color: var(--primary); + text-decoration: none; + font-weight: 600; + font-size: 0.95rem; + background: var(--glass); + transition: all 0.25s ease; +} +.see-more-btn:hover { + border-color: var(--accent); + color: white; + background: var(--accent); + transform: translateY(-1px); +} + +/* Make excerpt more compact in preview cards */ +.session-preview .session-preview-excerpt { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* Session preview grid (compact) */ +.session-preview-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1.25rem; + margin-bottom: 2rem; +} + +/* Compact cards inside session preview */ +.session-preview .session-preview-card { + padding: 1.25rem; +} + +.session-preview-card { + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: 20px; + padding: 2rem; + transition: all 0.4s ease; + position: relative; + overflow: hidden; + animation: fadeInUp 0.6s ease forwards; + opacity: 0; +} + +.session-preview-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, var(--accent), var(--accent-hover)); + transform: scaleX(0); + transition: transform 0.4s ease; +} + +.session-preview-card:hover::before { + transform: scaleX(1); +} + +.session-preview-card:hover { + transform: translateY(-8px); + box-shadow: 0 15px 35px var(--shadow); + border-color: var(--accent); +} + +.session-preview-badge { + display: inline-block; + padding: 6px 14px; + background: rgba(102, 126, 234, 0.15); + color: var(--accent); + border-radius: 20px; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 1rem; +} + +.session-preview-time { + display: flex; + align-items: center; + gap: 0.8rem; + margin-bottom: 1rem; + color: var(--text-dim); + font-size: 0.9rem; +} + +.preview-time { + font-weight: 700; + color: var(--accent); +} + +.preview-duration { + opacity: 0.8; +} + +.session-preview-title { + font-size: 1.4rem; + font-weight: 700; + color: var(--primary); + margin-bottom: 1rem; + line-height: 1.3; +} + +.session-preview-excerpt { + color: var(--text-dim); + line-height: 1.7; + margin-bottom: 1.5rem; + font-size: 0.95rem; +} + +.session-preview-speaker { + display: flex; + align-items: center; + gap: 1rem; + padding-top: 1.5rem; + border-top: 1px solid var(--glass-border); +} + +.preview-speaker-avatar { + width: 50px; + height: 50px; + border-radius: 50%; + object-fit: cover; + border: 2px solid var(--accent); + box-shadow: 0 3px 10px rgba(102, 126, 234, 0.3); +} + +.preview-speaker-name { + font-weight: 700; + color: var(--primary); + font-size: 0.95rem; + margin-bottom: 0.2rem; +} + +.preview-speaker-role { + font-size: 0.85rem; + color: var(--text-muted); +} + +/* CTA Section */ +.session-preview-cta { + text-align: center; + margin-top: 3rem; +} + +.session-preview-cta .cta-button { + display: inline-flex; + align-items: center; + gap: 0.8rem; + padding: 18px 40px; + font-size: 1.1rem; + margin-bottom: 1rem; +} + +.cta-arrow { + transition: transform 0.3s ease; +} + +.session-preview-cta .cta-button:hover .cta-arrow { + transform: translateX(5px); +} + +.cta-subtitle { + color: var(--text-muted); + font-size: 0.95rem; +} + +/* Responsive */ +@media (max-width: 768px) { + #session { + padding: 80px 20px; + } + + .session-preview-grid { + grid-template-columns: 1fr; + gap: 1.5rem; + } + + .session-preview-card { + padding: 1.5rem; + } + + .session-preview-title { + font-size: 1.2rem; + } + + .carousel-slide img { + height: 300px; + } + + .carousel-button { + width: 40px; + height: 40px; + font-size: 1.2rem; + } +} + +@media (max-width: 480px) { + .session-preview-speaker { + flex-direction: column; + align-items: flex-start; + } +} + +/* --- UPDATED FOOTER CSS --- */ +footer { + background-color: var(--bg-dark); + padding: 2.5rem 50px; + margin-top: auto; + width: 100%; + position: relative; +} + +/* Adds the decorative gradient line at the top */ +footer::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); +} + +/* This is the main wrapper created by your JS */ +.footer-content { + width: 100%; + max-width: 1200px; + margin: 0 auto; + + /* CHANGE: This section is updated for centering */ + display: flex; + flex-direction: column; /* Stacks the items vertically */ + justify-content: center; /* Centers the stack horizontally */ + align-items: center; /* Aligns items in the center */ + gap: 1.5rem; /* Space between social links and copyright */ +} + +.social-links { + display: flex; + gap: 1rem; +} + +/* Styling for the social link "pill" buttons */ +.social-link { + color: var(--text-dim); + background-color: transparent; + font-size: 0.875rem; + font-weight: 500; + text-decoration: none; + padding: 0.6rem 1.5rem; + border: 1px solid var(--glass-border); + border-radius: 50px; /* Creates the pill shape */ + transition: all 0.3s ease-in-out; + background-image: none; + + /* Required for the hover effect */ + position: relative; + z-index: 1; + overflow: hidden; +} + +/* Copied hover sweep from .cta-button to ensure consistency and fix broken effect */ +footer .social-link { + z-index: 0; +} + +footer .social-link::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent); + transition: left 0.5s ease; + pointer-events: none; +} + +footer .social-link:hover::before { + left: 100%; +} + +footer .social-link:hover { + color: var(--primary); + transform: translateY(-3px); + border-color: var(--accent); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15); +} + +.copyright { + color: var(--text-dim); + font-size: 0.9rem; + text-align: center; +} + +@media (max-width: 992px) { + .countdown-title { + font-size: 2.5rem; + } + + .timer-number { + font-size: 3rem; + } + + .event-date { + font-size: 1.5rem; + } + + .venue-content { + flex-grow: 1; + } + + .venue-info { + order: 1; + } + + .venue-map { + order: 2; + height: 400px; + } +} + +@media screen and (max-width: 850px) { + .venue-content { + width: 100%; + } + + .venue-info, + .venue-map { + flex-grow: 1; + flex-basis: 0; + min-width: 100%; + } +} + +@media (max-width: 768px) { + .nav-content { + padding: 0 16px; + position: static; /* Let nav be the positioned container so dropdown can span viewport */ + } + + .menu-toggle { + display: flex; + z-index: 1001; + } + + .nav-links { + position: absolute; + top: calc(100% + 12px); + left: 16px; + right: 16px; + width: calc(100vw - 32px); + background: rgba(37, 37, 38, 0.9); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + flex-direction: column; + align-items: stretch; + gap: 8px; + border-radius: 14px; + border: 1px solid rgba(255, 255, 255, 0.18); + box-shadow: 0 24px 56px rgba(0, 0, 0, 0.55); + padding: 12px; + opacity: 0; + visibility: hidden; + transform: translateY(10px) scale(0.98) translateZ(0); + transform-origin: top center; + transition: opacity 260ms cubic-bezier(0.22, 1, 0.36, 1), transform 260ms cubic-bezier(0.22, 1, 0.36, 1), visibility 260ms; + will-change: opacity, transform; + backface-visibility: hidden; + z-index: 1000; + } + + .nav-links::before { + content: ''; + position: absolute; + top: -8px; + right: 18px; + width: 16px; + height: 16px; + background: rgba(37, 37, 38, 0.85); + border-top: 1px solid rgba(255, 255, 255, 0.2); + border-left: 1px solid rgba(255, 255, 255, 0.2); + transform: rotate(45deg) translateY(-2px) scale(0.98); + opacity: 0; + transition: opacity 260ms cubic-bezier(0.22, 1, 0.36, 1), transform 260ms cubic-bezier(0.22, 1, 0.36, 1); + will-change: opacity, transform; + z-index: -1; + } + + .nav-links.active::before { + opacity: 1; + transform: rotate(45deg) translateY(0) scale(1); + } + + .nav-links.active { + opacity: 1; + visibility: visible; + transform: translateY(0) scale(1); + } + + .nav-links a { + font-size: 1rem; + padding: 12px 16px; + border-radius: 10px; + text-align: left; + width: 100%; + /*min-height: 50px;*/ + line-height: 30px; + display: block; + color: var(--text-dim); + background-color: rgba(255, 255, 255, 0.06); + transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, transform 0.12s ease; + } + + .nav-links a:hover, + .nav-links a:focus { + background-color: rgba(255, 255, 255, 0.12); + color: var(--primary); + } + + .nav-links a:active { + transform: scale(0.99); + } + + .nav-links a.active, + .nav-links a[aria-current="page"] { + background: linear-gradient(to right, #6610f2, #fd7e14); + color: #fff; + } + + .nav-links a:focus-visible { + outline: none; + box-shadow: 0 0 0 2px var(--accent); + } + + .nav-links a::after { + display: none; + } + + /* Light theme overrides for mobile menu items */ + [data-theme="light"] .nav-links { + background: rgba(255, 255, 255, 0.9); + border-color: rgba(0, 0, 0, 0.08); + } + + [data-theme="light"] .nav-links a { + background-color: rgba(0, 0, 0, 0.04); + } + + [data-theme="light"] .nav-links a:hover, + [data-theme="light"] .nav-links a:focus { + background-color: rgba(0, 0, 0, 0.08); + color: var(--primary); + } + + [data-theme="light"] .nav-links::before { + background: rgba(255, 255, 255, 0.9); + border-top-color: rgba(0, 0, 0, 0.08); + border-left-color: rgba(0, 0, 0, 0.08); + } + + body.menu-open { + overflow: hidden; + } + + .menu-toggle.active span:nth-child(1) { + transform: rotate(45deg) translate(7px, 7px); + } + + .menu-toggle.active span:nth-child(2) { + opacity: 0; + } + + .menu-toggle.active span:nth-child(3) { + transform: rotate(-45deg) translate(7px, -7px); + } + + /* Speaker Modal */ + .speaker-modal { + width: 95%; + max-height: 90vh; + } + + .speaker-modal-content { + padding: 25px; + } + + .speaker-modal-header { + flex-direction: column; + text-align: center; + } + + .speaker-modal-image { + width: 120px; + height: 120px; + } + + .speaker-modal-name { + font-size: 1.5rem; + } + + /* Countdown */ + .countdown { + padding: 80px 20px; + } + + .timer-number { + font-size: 2.5rem; + } + + .timer-label { + font-size: 0.8rem; + } + + /* Venue */ + .venue { + padding: 80px 20px; + } + + /* Footer */ + footer { + padding: 2rem 25px; + } +} + + +/* Fade-in animations */ +.fade-in-section { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.fade-in-section.visible { + opacity: 1; + transform: translateY(0); +} + +/* Back to top button */ +.back-to-top { + position: fixed; + bottom: 30px; + right: 30px; + width: 50px; + height: 50px; + background: linear-gradient(135deg, #667eea, #764ba2); + border: none; + border-radius: 50%; + color: white; + font-size: 1.5rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); + transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); + opacity: 0; + visibility: hidden; + transform: scale(0); + z-index: 1000; +} + +.back-to-top.visible { + opacity: 1; + visibility: visible; + transform: scale(1); +} + +.back-to-top:hover { + transform: scale(1.1) translateY(-3px); +} + +/* Enhanced loader */ +.loader-overlay { + position: fixed; + inset: 0; + background: #1e1e1e; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 10000; + transition: opacity 0.5s ease; +} + +.loader-overlay.hidden { + opacity: 0; + pointer-events: none; +} + +.loader-logo::before { + content: '{ }'; + font-size: 3rem; + font-weight: bold; + background: linear-gradient(135deg, #667eea, #764ba2); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: pulse 2s ease-in-out infinite; +} + +.loader-progress { + width: 300px; + height: 4px; + background: rgba(255, 255, 255, 0.1); + border-radius: 10px; + overflow: hidden; + margin: 2rem 0 1rem; +} + +.loader-progress-bar { + height: 100%; + background: linear-gradient(90deg, #667eea, #764ba2); + border-radius: 10px; + width: 0%; + transition: width 0.3s ease; +} + +.loader-text { + color: rgba(255, 255, 255, 0.7); + font-size: 0.9rem; +} + +/* Keyboard navigation focus */ +body.keyboard-nav *:focus { + outline: 2px solid #667eea; + outline-offset: 2px; +} + +/* Ripple animation */ +@keyframes ripple-animation { + to { + transform: scale(4); + opacity: 0; + } +} + +/* Mobile menu overlay */ +body.menu-open::before { + content: ''; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); /* Darken the background slightly */ + z-index: 998; /* Below nav-links but above content */ + animation: fadeIn 0.3s ease; +} + +[data-theme="light"] #why-jdc .section-title.gradient-text { + color: #000; +} + +/* Sponsors Section */ +#sponsors { + margin: 0 auto; + text-align: center; +} + +.sponsors-header { + margin-bottom: 60px; + font-size: 2rem; + font-weight: 700; +} + +/* Horizontal flex layout */ +.sponsors-grid { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 40px; +} + +/* Rounded rectangle sponsor card */ +.sponsor-card { + background: #ffffff; /* white background */ + border-radius: 20px; /* rounded corners */ + padding: 40px 60px; /* bigger card */ + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.3s ease, box-shadow 0.3s ease, background-color 0.3s ease; + min-width: 300px; + max-width: 400px; + flex-grow: 1; + position: relative; + overflow: hidden; +} + +.sponsor-card:hover { + background: rgba(255, 255, 255, 0.95); + box-shadow: 0 5px 20px rgba(0, 0, 0, 0.25), + 0 0 30px rgba(255, 0, 100, 0.5), + 0 0 50px rgba(255, 0, 100, 0.4); + transform: translateY(-8px); +} + +[data-theme="dark"] .sponsor-card:hover { + box-shadow: 0 5px 20px rgba(0, 0, 0, 0.25), + 0 0 30px rgba(0, 255, 208, 0.5), + 0 0 50px rgba(58, 250, 170, 0.4); +} + +/* Logo styling */ +.sponsor-logo { + object-fit: contain; +} + +[data-theme="dark"] .session-preview .section-background { + background: #2c2c2c; +} + + +/* Inline see more link inside preview abstract */ +.inline-see-more { + color: var(--accent); + font-weight: 700; + text-decoration: none; + white-space: nowrap; +} +.inline-see-more:hover, +.inline-see-more:focus-visible { + color: var(--accent-hover); + text-decoration: underline; +} diff --git a/2025/assets/data/payload.json b/2025/assets/data/payload.json new file mode 100644 index 0000000..cbde8e4 --- /dev/null +++ b/2025/assets/data/payload.json @@ -0,0 +1,520 @@ +{ + "hero": { + "title": "Java Developers' Conference 2025", + "edition": "11th Edition", + "cta": { + "text": "See you at JDC!", + "link": "https://tickets.jugbd.org" + } + }, + "about": { + "title": "Learning, Connecting, and Growing Together", + "description": "

The Java Developers’ Conference is Bangladesh’s premier community-driven software event, proudly organized by the Bangladesh Java User Group. It brings developers and technology enthusiasts together to explore the evolving world of Java and its ecosystem—covering everything from modern frameworks and cloud-native development to architecture, performance, and beyond.

This event brings the entire Java community under one roof, creating a space to talk, share ideas, learn from each other, and build valuable connections. Whether you’re a seasoned engineer or just beginning your Java journey, JDC is where you’ll learn, get inspired, and be part of something bigger.

", + "image": "assets/images/backgrounds/speaker1.jpg" + }, + "gallery": [ + "assets/images/gallery/00-slider.jpg", + "assets/images/gallery/01-slider.jpg", + "assets/images/gallery/02-slider.jpg", + "assets/images/gallery/03-slider.jpg", + "assets/images/gallery/04-slider.jpg", + "assets/images/gallery/05-slider.jpg", + "assets/images/gallery/06-slider.jpg", + "assets/images/gallery/07-slider.jpg", + "assets/images/gallery/08-slider.jpg", + "assets/images/gallery/09-slider.jpg", + "assets/images/gallery/10-slider.jpg", + "assets/images/gallery/11-slider.jpg", + "assets/images/gallery/12-slider..jpg", + "assets/images/gallery/13-slider..jpg", + "assets/images/gallery/14-slider..jpg" + ], + "speakers": [ + { + "fullName": "A N M Bazlur Rahman", + "name": "bazlur_rahman", + "bio": "

A N M Bazlur Rahman is a Java Champion, Senior Staff Software Engineer at Hammerspace, and the founder of the Bangladesh Java User Group (JUGBD). He’s an active contributor to the global Java community, a published author of Modern Concurrency in Java with O’Reilly Media, and a contributing editor at InfoQ and Foojay.io.

\n

With over a decade of experience in distributed systems and backend development, Bazlur focuses on modern Java, concurrency, and large-scale system design. He’s a frequent speaker at international conferences, where he helps developers understand how to write efficient, concurrent, and elegant Java code.

\n

When he’s not coding or writing, Bazlur mentors new developers and contributes to open-source projects that strengthen the Java ecosystem.

", + "talkTitle": "Your Java Code in the Fastlane: Project Loom", + "abstract": "Project Loom introduces virtual threads, lightweight threads that aim to dramatically reduce the effort of writing, maintaining, and monitoring high-throughput concurrent applications with the Java platform.\n\nWe need threads to achieve high throughput. However, threads are not cheap and are limited in number. To get around this problem, various alternatives such as the reactive programming style have emerged. These techniques bypass creating a lot of threads at the expense of more difficult debugging. This makes developers grumpy. However, with virtual threads, we get the best of both worlds, cheap, lightweight threads and easy debugging, which would make developers happy again.\n\nThis talk will explore what virtual threads are, how they are implemented, how they solve our modern problems and what, if any, shortcomings there are.\n\n", + "twitter": "bazlur_rahman", + "linkedin": "https://www.linkedin.com/in/bazlur/", + "website": "https://bazlur.ca/", + "title": "Java Champion | Software Engineer", + "company": "@Hammerspace", + "companyWebsite": "https://hammerspace.com/", + "image": "assets/images/speakers/rokon.png" + }, + { + "fullName": "Minhajul Abedin", + "name": "minhajul_abedin", + "bio": "

Minhajul Abedin is the Chief Technology Officer and Enterprise Software Architect at BRAC IT. With a strong passion for excellence in planning, design, and execution, he has led multiple high-impact projects across fintech, cloud, and enterprise software domains.

Over the years, Minhajul has guided teams in building scalable platforms serving millions of users, integrated AWS-based Big Data solutions for global clients like Widespace AB, and re-architected complex enterprise and social systems for better scalability and performance. He has also consulted for organizations such as a2i (National Portal) and Implevista Ltd, Denmark.

His expertise spans architecture design, distributed systems, BI solutions, and DevOps. Minhajul’s technical leadership continues to shape innovative and resilient software systems that drive organizational growth.

", + "talkTitle": "TBD", + "abstract": "TBD", + "twitter": "", + "linkedin": "https://www.linkedin.com/in/minhajulabedin/", + "website": "", + "title": "Chief Technology Officer & Enterprise Software Architect", + "company": "@BRAC IT", + "companyWebsite": "https://www.bracits.com/", + "image": "assets/images/speakers/minhaj.jpeg" + }, + { + "fullName": "Mozammel Haque", + "name": "mozammel_haque", + "bio": " Mozammel Haque has been involved in creating software solutions for more than 20 years now. Starting from creating the first 3D racing game back in 2002, namely 'Dhaka Racing', Mozammel has worked on developing softwares that target hyper growth oriented Silicon Valley based startups, as well as creating solutions for larger enterprises which require high scalability and reliability. At bKash, Mozammel is leading Software Research and Engineering team which is taking care of bKash's in-house software development needs. Apart from work, he is a cycling and health enthusiast and mostly bikes around everywhere in Dhaka.", + "talkTitle": "TBD\n", + "abstract": "TBD", + "twitter": "mozammel", + "linkedin": "https://www.linkedin.com/in/mozammel/", + "website": "https://mozammelhaque.com/", + "title": "EVP, Head of Department, Software Research and Engineering, Product & Technology", + "company": "@bKash Limited", + "companyWebsite": "https://www.bkash.com/", + "image": "assets/images/speakers/moz.jpg" + }, + { + "fullName": "Mojahedul Hoque Abul Hasanat", + "name": "mojahedul_hasanat", + "bio": "


Mojahedul Hoque Abul Hasanat works at Dynamic Solution Innovators as the Chief Technology Officer. He is an Application Architect and Developer. He has 20 years of experience in the design and development of large scale applications in Java, systems applications in Perl, C and assembly, and expert knowledge on Spring Framework, Hibernate, and WebLogic.", + "talkTitle": "TBD\n", + "abstract": "TBD", + "twitter": "just_unix", + "linkedin": "https://www.linkedin.com/in/mojahedul/", + "website": "https://github.com/unixdev", + "title": "Chief Technology Officer", + "company": "@Dynamic Solution Innovators", + "companyWebsite": "https://www.dsinnovators.com", + "image": "assets/images/speakers/hasanat.jpg" + }, + { + "fullName": "Shaaf Syed", + "name": "shaaf_syed", + "bio": "

Shaaf Syed is a Developer Advocate at Red Hat, Technical Editor at InfoQ, and author at shaaf.dev. He is passionate about open source and focuses on Cloud, Software Defined Data Center, DevOps and Continuous Delivery.

He began his career as a Software Engineer specializing in build engineering across Solaris, Linux, and Windows. Later he moved into Continuous Integration for C/Java components, applying that experience across many projects as tools evolved. Over the years he has worked with multiple languages (Java, .NET, etc.) as tools to reach business goals.

Beyond his work, he actively participates in local meetups and speaks at conferences on Cloud, DevOps and open source technologies.

Find more about him via shaaf.dev and his SlideShare.

", + "talkTitle": "TBD", + "abstract": "TBD", + "twitter": "", + "linkedin": "https://www.linkedin.com/in/shaaf", + "website": "https://shaaf.dev", + "title": "Sr. Principal Developer Advocate | Red Hat", + "company": "@Red Hat", + "companyWebsite": "https://www.redhat.com", + "image": "assets/images/speakers/shaaf.jpg" + } + ], + "whyJdc": { + "why": { + "title": "Be Part of Bangladesh’s Biggest Java Gathering —", + "items": [ + { + "title": "Meet Java Enthusiasts", + "body": "Connect with passionate developers, architects, and Java lovers over great coffee and good conversations." + }, + { + "title": "Engage in Meaningful Conversations", + "body": "Exchange ideas, share your experiences, and discuss your favorite Java technologies with people who truly get it." + }, + { + "title": "Learn from Experts", + "body": "Gain insights from world-class Java professionals and community leaders through inspiring talks and hands-on sessions." + }, + { + "title": "Get Inspired to Grow", + "body": "Discover new tools, frameworks, and trends shaping the future of Java and take your skills to the next level." + }, + { + "title": "Experience the Community Spirit", + "body": "Enjoy an event filled with learning, networking, and laughter as the Java community comes together under one roof." + }, + { + "title": "Win and Have Fun", + "body": "Take part in interactive sessions, challenges, and activities and maybe even walk away with some cool prizes!" + } + ] + } + }, + "countdown": { + "title": "The Conference starts in...", + "targetDate": "2025-12-06T09:59:59", + "subsection": { + "date": "At 10:00 on 6th December", + "title": "Get realtime event updates", + "body": "Always keep an eye on the {{link}} group on Facebook", + "link": { + "text": "JUGBD", + "url": "https://www.facebook.com/groups/jugbd" + } + } + }, + "sponsors": [ + { + "id": "dsi", + "name": "Dynamic Solution Innovators", + "logo": "assets/images/sponsor/dsi-logo.svg", + "website": "https://www.dsinnovators.com/" + } + ], + "sessionPreview": [ + "From 21 to 25: What Modern Java Looks Like Today", + "Building Platforms, Breaking Barriers: My DevOps Journey" + ], + "sessions": [ + { + "time": "10:30 AM", + "duration": "40 min", + "track": "Technical", + "title": "From 21 to 25: What Modern Java Looks Like Today", + "abstract": "

Java has changed faster in the last few years than it ever has before. Moving from Java 21 to Java 25 brings meaningful improvements across the language, runtime, and developer experience. This session walks through the changes that matter in real projects. We’ll look at the refinements in pattern matching, records, and unnamed patterns, explore how virtual threads and structured concurrency reshape server-side design, and see the first practical impact of Project Valhalla’s primitive classes. We’ll also cover developer-friendly additions like Compact Source Files and instance main methods, which make Java lighter and easier to use for scripting and quick utilities. Along the way, we’ll highlight updates to the Foreign Function & Memory API and the JVM performance gains that arrive in the latest release. By the end, you’ll have a clear picture of what modern Java looks like today and how to adopt these features confidently.

", + "speaker": { + "name": "A N M Bazlur Rahman", + "role": "Senior Staff Software Engineer | Hammerspace", + "image": "./assets/images/speakers/rokon.png", + "bio": "" + }, + "tags": [ + "Java 21/25", + "Virtual Threads", + "Project Valhalla", + "Language Updates" + ] + }, + { + "time": "11:15 AM", + "duration": "40 min", + "track": "Technical", + "title": "Context Engineering with Java and DuckDB", + "abstract": "

Now that LLMs dominate headlines, what is the Java developer’s role? An LLM is an ocean of knowledge with occasional illusions. It does not know your business rules, policies, or transaction semantics. If you want it to help real accountants or domain experts, you must supply your context and the reasoning over that context. That is context engineering.

Just as an RDBMS holds application metadata, LLM applications need two additional stores. A Graph DB captures relationships and policy scope: parent, sibling, neighbor, depth. A Vector DB holds domain documents and records for semantic retrieval. For any goal, you assemble the right facts and the reasoning path, then feed both to the model.

In this session we build a thin Context ORM in Java that can parse domain documents, index entities and relationships into a Graph DB, embed documents and records into a Vector DB, and provide a retrieval mechanism that stitches the right context and reasoning into prompts. We use Spring AI, DuckDB with vector search, and a small business domain with dummy data. You will see how to ground answers in your rules, test them, audit them, and make LLM output reliable for real work.

", + "speaker": { + "name": "Mahmudur R Manna", + "role": "Associate Director | EY", + "image": "./assets/images/speakers/manna.jpg", + "bio": "

Mahmudur R Manna is a Bangladeshi engineer, author, and entrepreneur with over two decades of global experience in designing and building data platforms, cloud-native and distributed systems, big-data analytics, and SaaS solutions. In recent years, he has focused on creating AI-driven products and enterprise AI systems.

As the founder of the Decision-Driven Software Engineering (DDSE) Foundation, Manna promotes decision-centric, human-AI collaboration in software delivery. He is the author of Enterprise AI: Strategic Blueprint for Purple People and an active open-source contributor through the DDSE Foundation and other projects on GitHub. His thought leadership extends to Medium, where he publishes articles on AI strategy, engineering methodologies, and organizational design, along with research exploring the future of AI-assisted software development.

Manna’s work blends deep hands-on engineering expertise with the ability to transform complex technical challenges into scalable, human-aligned solutions.

" + + }, + "tags": [ + "Spring AI", + "DuckDB", + "Vector Search", + "LLM Engineering" + ] + }, + { + "time": "12:20 AM", + "duration": "40 min", + "track": "Technical", + "title": "Resilience Engineering in Java Systems: Patterns That Keep Your App Alive", + "abstract": "

Resilience Engineering in Java systems focuses on building applications that continue to function even when parts of the system fail. It emphasizes designing for failure from the start rather than reacting after problems occur. Java developers use key resilience patterns—such as retries, exponential backoff, fallbacks, rate limiting, bulkheads, and circuit breakers—to ensure systems remain stable under stress. Tools like Resilience4j, Spring Cloud, and MicroProfile Fault Tolerance make it easier to apply these patterns in production.

Modern distributed systems face challenges like network latency, partial outages, and dependency failures, making resilience essential in microservice architectures. Circuit breakers help isolate failing components, preventing cascading failures. Bulkheads create boundaries between services so that one heavy workload doesn’t overload the entire system. Timeouts and rate limiting protect resources from being overwhelmed during traffic spikes or malicious requests.

Observability—metrics, logs, and distributed tracing—is also a critical part of resilience engineering, enabling teams to detect failures early and respond quickly. Chaos engineering practices validate resilience by intentionally injecting failures to observe system behavior. Overall, resilience engineering ensures Java applications remain reliable, responsive, and fault-tolerant, even in unpredictable real-world conditions.

", + "speaker": { + "name": "Md. Habibur Rahman,", + "role": "Engineering Manager | DSi", + "image": "./assets/images/speakers/habib.png", + "bio": "" + }, + "tags": [ + "Java", + "Microservices", + "Distributed Systems", + "Resilience4j" + ] + }, + { + "time": "2:00 PM", + "duration": "40 min", + "track": "Technical", + "title": "Inside Lucene: Algorithms and Data Structures Behind Modern Enterprise Search", + "abstract": "It’s safe to say that more than half the search on the internet is powered by Lucene — Twitter, LinkedIn, Netflix, Wikipedia, Reddit, Airbnb, Slack… and more. Getting started with Elasticsearch or Solr (both built on Lucene) is easy, but real performance tuning, relevance engineering, and scaling require understanding what’s happening under the hood.\n\nIn this session, we’ll dip into Lucene’s most important algorithms and data structures and see how they impact performance and efficiency. Covering everything in 30 minutes isn’t possible, but we’ll focus on the essentials — and if you’re curious about the rest… well, you’ll just have to catch up with me over a cup of tea, lol. ☕", + "speaker": { + "name": "Isfar Sifat", + "role": "Senior Software Engineer | Freterium YC 21", + "image": "./assets/images/speakers/avatar.png", + "bio": "" + }, + "tags": [ + "Search Engineering", + "Lucene", + "Elasticsearch", + "Distributed Systems" + ] + }, + + { + "time": "2:40 PM", + "duration": "40 min", + "track": "Academia", + "title": "Java in Academia and Research", + "abstract": "

This lecture explores the significant role of the Java programming language in modern academic research, highlighting its strengths in portability, performance, and ecosystem richness. It discusses how Java supports diverse research domains including optimization, simulation, machine learning, big data analytics, and scientific computing. Key libraries, frameworks, and tools are reviewed to demonstrate how Java enables fast prototyping, reproducible experiments, and scalable computational studies. The talk also emphasizes best practices for writing research-grade Java code, from experiment management to benchmarking and documentation. Overall, the lecture positions Java as a versatile, reliable, and powerful language for conducting rigorous and impactful academic research.

", + "speaker": { + "name": "Shah Mostafa Khaled, Ph.D.", + "role": "Associate Professor | Institute of Information Technology, University of Dhaka", + "image": "./assets/images/speakers/khaled.jpg", + "bio": "

Dr. Shah Mostafa Khaled is an Associate Professor at the Institute of Information Technology (IIT), University of Dhaka, Bangladesh. He holds a PhD in Management Science and Engineering from the University of Waterloo (2018–2024), where he completed his doctoral thesis titled Shipment Consolidation in Hub Location Modelling under the supervision of Professors James H. Bookbinder and Sibel A. Alumur. He previously earned a Master’s in Computer Science from the University of Lethbridge, Canada, as well as a BSc and MSc in Computer Science and Engineering from the University of Dhaka. His research spans optimization, operations research, machine learning, algorithms and data structures, and combinatorial problem solving, and he leads the Optimization Research Group at IIT DU.

" + + }, + "tags": [ + "Academia", + "Research", + "CS Education" + ] + }, + { + "time": "3:20 PM", + "duration": "40 min", + "track": "Technical", + "title": "Building Platforms, Breaking Barriers: My DevOps Journey", + "abstract": "

In this talk, I share my decade-long journey through the evolving world of DevOps and platform engineering—an experience shaped by curiosity, continuous learning, and a commitment to building systems that scale. Starting as a Linux enthusiast, I gradually transitioned into modern DevOps practices, mastering automation, infrastructure-as-code, and cloud-native architectures. Over the years, I have had the opportunity to design and lead the implementation of enterprise-grade Kubernetes platforms, containerized application ecosystems, and high-availability database clusters that support mission-critical workloads.

Throughout my career, I have worked closely with cross-functional teams to break operational silos, streamline development pipelines, and introduce DevSecOps principles across organizations. My roles—as a DevOps Engineer, Principal DevOps Architect, and now Head of Platform Architecture and DevOps Engineering—have enabled me to blend strategy with hands-on expertise. This includes enabling CI/CD adoption, leading cost-optimization initiatives, setting up observability stacks, and mentoring engineers to build strong platform mindsets.

As a Red Hat Certified Architect and Kubernetes specialist, I have focused on simplifying complex infrastructure problems while ensuring security, resilience, and operational excellence. This talk aims to highlight key lessons from building platforms from scratch, overcoming organizational and technical barriers, and navigating the human side of DevOps transformation.

Attendees will gain insights into practical strategies, leadership experiences, and technical patterns that can help them accelerate their own DevOps journey—whether they are just starting out or scaling their platform engineering capabilities.

", + "speaker": { + "name": "Md. Rakibul Hassan", + "role": "Senior General Manager | Robi Axiata PLC", + "image": "./assets/images/speakers/rakibul.jpg", + "bio": "" + }, + "tags": [ + "DevOps", + "Platform Engineering", + "Kubernetes" + ] + }, + { + "time": "4:20 PM", + "duration": "40 min", + "track": "Technical", + "title": "Turning Chaos Into Clarity: Refactoring Legacy Code for Maintainability", + "abstract": "

Working with legacy code often feels like navigating a minefield—every change carries uncertainty, hidden dependencies, and the fear of breaking something that once worked. It’s slow, frustrating, and sometimes exhausting. Yet refactoring is the only way to restore clarity, bring structure back into the system, and make the codebase future-proof.

This session will walk you through practical techniques for identifying few code smells, reducing technical debt, and modernizing old structures without breaking what already works. The goal is simple: turn chaos of legacy code into clean, readable, testable and maintainable codebase that supports faster development, fewer bugs, and long-term stability.

", + "speaker": { + "name": "Zohirul Alam Tiemoon", + "role": "CEO & Co-founder | Nerd Castle Limited", + "image": "./assets/images/speakers/taemoon.jpg", + "bio": "

As a seasoned technology leader with over 24 years of experience in the ICT sector, I have a proven track record in leading technical vision and strategy, and developing enterprise and MVP solutions. My expertise spans system design, software engineering, and creating engaging experiences for users worldwide.

Previously, I served as the Senior Vice President at Goama, where I spearheaded the development and delivery of scalable gaming solutions as a service, managing a diverse team of software engineers, designers, and testers. Under my leadership, we established a culture of collaboration, creativity, and excellence, significantly enhancing the gaming experience for millions of users.

I hold a B.Sc. in Computer Science & Engineering from Shahjalal University of Science and Technology. Over the years, I have refined my skills in web applications, software development, object-oriented programming, software design principles and patterns, Android app development, and agile methodologies.

I have also delivered corporate training for prestigious organizations and projects such as the Bangladesh Association of Software & Information Services (BASIS), Beximco Pharma, the LICT project, and the ICT Ministry of the Bangladesh Government—training over 15,000 software professionals. My designs for enterprise software solutions have successfully added value to various clients’ businesses.

I am passionate about using my skills to solve complex problems, improve lives, and create a positive impact through technology. My hands-on expertise includes developing .NET applications, designing relational databases, and crafting distributed systems with a strong focus on refactoring and unit testing, guided by principles of test-driven development (TDD).

I have written a book on Object-Oriented Programming (অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং) in Bangla: rokomari.com/book/212639/object-oriented-programming.

" + + }, + "tags": [ + "Refactoring", + "Legacy Code", + "Technical Debt", + "Clean Code" + ] + }, + { + "time": "5:40 PM", + "duration": "40 min", + "track": "Technical", + "title": "Frameworks? Nah. Let’s Just Write Java. Reclaiming simplicity, control, and architectural clarity.", + "abstract": "

Modern Java development often feels like sticking LEGO blocks together without understanding how they fit. We rely so heavily on frameworks like Spring that we forget the power of the language itself.

It’s time to discard the crutches. With the JDK more powerful than ever, do we really need all that extra weight? This talk is about building robust, production-ready software using nothing but standard Java. We will trade \"magic\" abstractions for discipline and design patterns. By the end of this session, you’ll see that you don't need a long dependency tree to build good software—you just need to master your language. Let’s get back to basics and see what Java can really do.

", + "speaker": { + "name": "Muhammad Abul Kasim", + "role": "Software Architect | Brac IT Limited", + "image": "./assets/images/speakers/kasim.jpg", + "bio": "

I’m a Software Architect with deep experience in designing and scaling high-performance distributed systems across diverse domains, including business applications and real-time messaging platforms. I thrive on solving complex architectural challenges—whether it’s optimizing ultra-low-latency data pipelines, building efficient event-driven systems, or refactoring legacy codebases into clean, modern, and extensible services.

My expertise spans runtime and OS internals, message brokers, RDBMS and NoSQL databases, microservices, Domain-Driven Design (DDD), CQRS, SaaS architectures, and high-concurrency systems. I balance pragmatic engineering with a long-term architectural vision, emphasizing clear abstractions, predictable performance, and systems that are easy to reason about and maintain.

I’m passionate about deep technical topics: memory models, lock-free algorithms, threading, custom serialization, distributed crawling, and even building device drivers for fun. I excel in environments where I can mentor engineering teams, shape technical strategy, and craft software that is both powerful and elegant.

Open to connecting on distributed systems, performance engineering, large-scale architecture, or the art of building software that lasts.

" + + }, + "tags": [ + "Core Java", + "Software Architecture", + "Design Patterns" + ] + } + ], + "ourTeam": [ + { + "fullName": "A N M Bazlur Rahman", + "linkedin": "https://www.linkedin.com/in/bazlur/", + "company": "@Hammerspace", + "companyWebsite": "http://www.hammerspace.com", + "image": "assets/images/team/team01.jpg" + }, + { + "fullName": "Mozammel Haque", + "linkedin": "https://www.linkedin.com/in/mozammel/", + "company": "@bKash Limited", + "companyWebsite": "https://www.bkash.com/", + "image": "assets/images/team/team02.jpg" + }, + { + "fullName": "Mukit Chowdhury", + "linkedin": "https://www.linkedin.com/in/mukit-chowdhury-492a94125/", + "company": "@Vivasoft Limited", + "companyWebsite": "http://www.vivasoftltd.com/", + "image": "assets/images/team/team03.jpg" + }, + { + "fullName": "Md. Nowshad Hasan Apu", + "linkedin": "https://www.linkedin.com/in/md-nowshad-hasan/", + "company": "@BizMotion", + "companyWebsite": "https://www.biz-motion.com/", + "image": "assets/images/team/team05.jpg" + }, + { + "fullName": "Abdullah Al Mamun Oronno", + "linkedin": "https://www.linkedin.com/in/oronno/", + "company": "@Index Exchange", + "companyWebsite": "https://www.indexexchange.com/li", + "image": "assets/images/team/team04.jpg" + }, + { + "fullName": "Mosharraf Hosain", + "linkedin": "https://www.linkedin.com/in/mh0s41n/", + "company": "@bKash Limited", + "companyWebsite": "https://www.bkash.com/", + "image": "assets/images/team/team06.jpg" + }, + { + "fullName": "C M Abdullah Khan", + "linkedin": "https://www.linkedin.com/in/cmabdullah/", + "company": "@IdeaScale", + "companyWebsite": "https://ideascale.com/", + "image": "assets/images/team/team07.jpg" + }, + { + "fullName": "Md Arif Hasan", + "linkedin": "https://www.linkedin.com/in/md-arif-hasan23/", + "company": "@Beyond Stories", + "companyWebsite": "https://www.linkedin.com/company/beyond-stories-bd/", + "image": "assets/images/team/team08.jpg" + }, + { + "fullName": "Md Ruhul Quddus", + "linkedin": "https://www.linkedin.com/in/shakkhor/", + "company": "@bKash Limited", + "companyWebsite": "https://www.bkash.com/", + "image": "assets/images/team/team09.jpg" + }, + { + "fullName": "S M Mahmudul Hasan", + "linkedin": "https://www.linkedin.com/in/tanvir-anjum-rifat-63977a229/", + "company": "@Therap (BD) Ltd.", + "companyWebsite": "https://therapbd.com/", + "image": "assets/images/team/team10.jpg" + }, + { + "fullName": "Tanvir Anjum Rifat", + "linkedin": "https://www.linkedin.com/in/s-m-mahmudul-hasan-a6bb0626/", + "company": "@BRAC IT", + "companyWebsite": "https://www.bracits.com/", + "image": "assets/images/team/team11.jpg" + }, + { + "fullName": "Md Shahriar Hasan", + "linkedin": "https://www.linkedin.com/in/shahriarhasan808/", + "company": "@TekSoi Software Ltd", + "companyWebsite": "https://www.linkedin.com/company/teksoi/", + "image": "assets/images/team/team12.jpg" + }, + { + "fullName": "Ali Hossain", + "linkedin": "https://www.linkedin.com/in/mowrajt/", + "company": "", + "companyWebsite": "", + "image": "assets/images/team/team13.jpg" + } + ], + "location": { + "title": "Venue", + "description": "Krishibid Institution Bangladesh", + "email": "info@jugbd.org", + "map": "https://maps.app.goo.gl/ksLLdcir4VQWv4jE9", + "mapEmbed": "", + "address": { + "name": "1st floor, KIB Auditorium", + "street": "KIB Complex, Khamar Bari Rd", + "city": "Dhaka, Bangladesh" + } + }, + "schedule": [ + { + "time": "10:00 – 10:30", + "session": "Opening + Welcome", + "speaker": "A N M Bazlur Rahman & DSI", + "isBreak": false + }, + { + "time": "10:30 – 11:10", + "session": "From 21 to 25: What Modern Java Looks Like Today", + "speaker": "A N M Bazlur Rahman", + "isBreak": false + }, + { + "time": "11:15 – 11:55", + "session": "Context Engineering with Java and DuckDB", + "speaker": "Mahmudur R Manna", + "isBreak": false + }, + { + "time": "12:00 – 12:20", + "session": "Coffee Break + Networking", + "speaker": "—", + "isBreak": true + }, + { + "time": "12:20 – 1:00", + "session": "Resilience Engineering in Java Systems: Patterns That Keep Your App Alive", + "speaker": "Md. Habibur Rahman", + "isBreak": false + }, + { + "time": "1:00 – 2:00", + "session": "Lunch Break + Johor Break", + "speaker": "—", + "isBreak": true + }, + { + "time": "2:00 – 2:40", + "session": "Inside Lucene: Algorithms and Data Structures Behind Modern Enterprise Search", + "speaker": "Isfar Sifat", + "isBreak": false + }, + { + "time": "2:45 – 3:25", + "session": "Java in Academia and Research", + "speaker": "Shah Mostafa Khaled, Ph.D.", + "isBreak": false + }, + { + "time": "3:30 – 4:10", + "session": "Building Platforms, Breaking Barriers: My DevOps Journey", + "speaker": "Md. Rakibul Hassan", + "isBreak": false + }, + { + "time": "4:10 – 4:30", + "session": "Asr Break + Coffee", + "speaker": "—", + "isBreak": true + }, + { + "time": "4:30 – 5:10", + "session": "Turning Chaos Into Clarity: Refactoring Legacy Code for Maintainability", + "speaker": "Zohirul Alam Tiemoon", + "isBreak": false + }, + { + "time": "5:10 – 5:40", + "session": "Maghrib Break + Snacks", + "speaker": "—", + "isBreak": true + }, + { + "time": "5:40 – 6:20", + "session": "Frameworks? Nah. Let's Just Write Java", + "speaker": "Muhammad Abul Kasim", + "isBreak": false + }, + { + "time": "6:40 – 7:10", + "session": "Panel Q&A / Discussion", + "speaker": "All Speakers", + "isBreak": false + } + ], + "footer": { + "social": [ + { + "name": "Facebook", + "link": "https://www.facebook.com/groups/jugbd" + }, + { + "name": "LinkedIn", + "link": "https://www.linkedin.com/groups/5072388/" + } + ], + "copyright": "© {{YYYY}} JugBD.org. All rights reserved." + } +} diff --git a/2025/assets/icons/android-chrome-192x192.png b/2025/assets/icons/android-chrome-192x192.png new file mode 100644 index 0000000..d3d3389 Binary files /dev/null and b/2025/assets/icons/android-chrome-192x192.png differ diff --git a/2025/assets/icons/favicon-16x16.png b/2025/assets/icons/favicon-16x16.png new file mode 100644 index 0000000..be11c27 Binary files /dev/null and b/2025/assets/icons/favicon-16x16.png differ diff --git a/2025/assets/icons/favicon-32x32.png b/2025/assets/icons/favicon-32x32.png new file mode 100644 index 0000000..1741033 Binary files /dev/null and b/2025/assets/icons/favicon-32x32.png differ diff --git a/2025/assets/icons/favicon.ico b/2025/assets/icons/favicon.ico new file mode 100644 index 0000000..e7808dd Binary files /dev/null and b/2025/assets/icons/favicon.ico differ diff --git a/2025/assets/images/gallery/00-slider.jpg b/2025/assets/images/gallery/00-slider.jpg new file mode 100644 index 0000000..9349279 Binary files /dev/null and b/2025/assets/images/gallery/00-slider.jpg differ diff --git a/2025/assets/images/gallery/01-slider.jpg b/2025/assets/images/gallery/01-slider.jpg new file mode 100644 index 0000000..b73a9a1 Binary files /dev/null and b/2025/assets/images/gallery/01-slider.jpg differ diff --git a/2025/assets/images/gallery/02-slider.jpg b/2025/assets/images/gallery/02-slider.jpg new file mode 100644 index 0000000..2191201 Binary files /dev/null and b/2025/assets/images/gallery/02-slider.jpg differ diff --git a/2025/assets/images/gallery/03-slider.jpg b/2025/assets/images/gallery/03-slider.jpg new file mode 100644 index 0000000..9ba39c1 Binary files /dev/null and b/2025/assets/images/gallery/03-slider.jpg differ diff --git a/2025/assets/images/gallery/04-slider.jpg b/2025/assets/images/gallery/04-slider.jpg new file mode 100644 index 0000000..5533f40 Binary files /dev/null and b/2025/assets/images/gallery/04-slider.jpg differ diff --git a/2025/assets/images/gallery/05-slider.jpg b/2025/assets/images/gallery/05-slider.jpg new file mode 100644 index 0000000..3a6cbca Binary files /dev/null and b/2025/assets/images/gallery/05-slider.jpg differ diff --git a/2025/assets/images/gallery/06-slider.jpg b/2025/assets/images/gallery/06-slider.jpg new file mode 100644 index 0000000..392228a Binary files /dev/null and b/2025/assets/images/gallery/06-slider.jpg differ diff --git a/2025/assets/images/gallery/07-slider.jpg b/2025/assets/images/gallery/07-slider.jpg new file mode 100644 index 0000000..132a4d8 Binary files /dev/null and b/2025/assets/images/gallery/07-slider.jpg differ diff --git a/2025/assets/images/gallery/08-slider.jpg b/2025/assets/images/gallery/08-slider.jpg new file mode 100644 index 0000000..271b571 Binary files /dev/null and b/2025/assets/images/gallery/08-slider.jpg differ diff --git a/2025/assets/images/gallery/09-slider.jpg b/2025/assets/images/gallery/09-slider.jpg new file mode 100644 index 0000000..fb01a2b Binary files /dev/null and b/2025/assets/images/gallery/09-slider.jpg differ diff --git a/2025/assets/images/gallery/10-slider.jpg b/2025/assets/images/gallery/10-slider.jpg new file mode 100644 index 0000000..6584b6e Binary files /dev/null and b/2025/assets/images/gallery/10-slider.jpg differ diff --git a/2025/assets/images/gallery/11-slider.jpg b/2025/assets/images/gallery/11-slider.jpg new file mode 100644 index 0000000..3e3dc1a Binary files /dev/null and b/2025/assets/images/gallery/11-slider.jpg differ diff --git a/2025/assets/images/gallery/12-slider..jpg b/2025/assets/images/gallery/12-slider..jpg new file mode 100644 index 0000000..2855ba6 Binary files /dev/null and b/2025/assets/images/gallery/12-slider..jpg differ diff --git a/2025/assets/images/gallery/13-slider..jpg b/2025/assets/images/gallery/13-slider..jpg new file mode 100644 index 0000000..a4275f1 Binary files /dev/null and b/2025/assets/images/gallery/13-slider..jpg differ diff --git a/2025/assets/images/gallery/14-slider..jpg b/2025/assets/images/gallery/14-slider..jpg new file mode 100644 index 0000000..772273c Binary files /dev/null and b/2025/assets/images/gallery/14-slider..jpg differ diff --git a/2025/assets/images/speakers/RezaRahman.png b/2025/assets/images/speakers/RezaRahman.png new file mode 100644 index 0000000..56e5157 Binary files /dev/null and b/2025/assets/images/speakers/RezaRahman.png differ diff --git a/2025/assets/images/speakers/abir.jpeg b/2025/assets/images/speakers/abir.jpeg new file mode 100644 index 0000000..99a9fe4 Binary files /dev/null and b/2025/assets/images/speakers/abir.jpeg differ diff --git a/2025/assets/images/speakers/anik.jpeg b/2025/assets/images/speakers/anik.jpeg new file mode 100644 index 0000000..e02387e Binary files /dev/null and b/2025/assets/images/speakers/anik.jpeg differ diff --git a/2025/assets/images/speakers/avatar.png b/2025/assets/images/speakers/avatar.png new file mode 100644 index 0000000..56286ae Binary files /dev/null and b/2025/assets/images/speakers/avatar.png differ diff --git a/2025/assets/images/speakers/habib.jpg b/2025/assets/images/speakers/habib.jpg new file mode 100644 index 0000000..39c934e Binary files /dev/null and b/2025/assets/images/speakers/habib.jpg differ diff --git a/2025/assets/images/speakers/habib.png b/2025/assets/images/speakers/habib.png new file mode 100644 index 0000000..00618be Binary files /dev/null and b/2025/assets/images/speakers/habib.png differ diff --git a/2025/assets/images/speakers/hasanat.jpg b/2025/assets/images/speakers/hasanat.jpg new file mode 100644 index 0000000..48f93b0 Binary files /dev/null and b/2025/assets/images/speakers/hasanat.jpg differ diff --git a/2025/assets/images/speakers/kasim.jpg b/2025/assets/images/speakers/kasim.jpg new file mode 100644 index 0000000..1de6055 Binary files /dev/null and b/2025/assets/images/speakers/kasim.jpg differ diff --git a/2025/assets/images/speakers/khaled.jpg b/2025/assets/images/speakers/khaled.jpg new file mode 100644 index 0000000..db682b6 Binary files /dev/null and b/2025/assets/images/speakers/khaled.jpg differ diff --git a/2025/assets/images/speakers/manna.jpg b/2025/assets/images/speakers/manna.jpg new file mode 100644 index 0000000..5930458 Binary files /dev/null and b/2025/assets/images/speakers/manna.jpg differ diff --git a/2025/assets/images/speakers/minhaj.jpeg b/2025/assets/images/speakers/minhaj.jpeg new file mode 100644 index 0000000..a8df61f Binary files /dev/null and b/2025/assets/images/speakers/minhaj.jpeg differ diff --git a/2025/assets/images/speakers/moz.jpg b/2025/assets/images/speakers/moz.jpg new file mode 100644 index 0000000..bdb2c66 Binary files /dev/null and b/2025/assets/images/speakers/moz.jpg differ diff --git a/2025/assets/images/speakers/oronno.png b/2025/assets/images/speakers/oronno.png new file mode 100644 index 0000000..1cbf71d Binary files /dev/null and b/2025/assets/images/speakers/oronno.png differ diff --git a/2025/assets/images/speakers/rakibul.jpg b/2025/assets/images/speakers/rakibul.jpg new file mode 100644 index 0000000..5bfc076 Binary files /dev/null and b/2025/assets/images/speakers/rakibul.jpg differ diff --git a/2025/assets/images/speakers/rokon.png b/2025/assets/images/speakers/rokon.png new file mode 100644 index 0000000..7a32624 Binary files /dev/null and b/2025/assets/images/speakers/rokon.png differ diff --git a/2025/assets/images/speakers/shaaf.jpg b/2025/assets/images/speakers/shaaf.jpg new file mode 100644 index 0000000..7aceb19 Binary files /dev/null and b/2025/assets/images/speakers/shaaf.jpg differ diff --git a/2025/assets/images/speakers/taemoon.jpg b/2025/assets/images/speakers/taemoon.jpg new file mode 100644 index 0000000..889ec76 Binary files /dev/null and b/2025/assets/images/speakers/taemoon.jpg differ diff --git a/2025/assets/images/speakers/zahur.jpg b/2025/assets/images/speakers/zahur.jpg new file mode 100644 index 0000000..4af4f28 Binary files /dev/null and b/2025/assets/images/speakers/zahur.jpg differ diff --git a/2025/assets/images/sponsor/dsi-logo.svg b/2025/assets/images/sponsor/dsi-logo.svg new file mode 100644 index 0000000..90f9a99 --- /dev/null +++ b/2025/assets/images/sponsor/dsi-logo.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2025/assets/images/team/team01.jpg b/2025/assets/images/team/team01.jpg new file mode 100644 index 0000000..7a32624 Binary files /dev/null and b/2025/assets/images/team/team01.jpg differ diff --git a/2025/assets/images/team/team02.jpg b/2025/assets/images/team/team02.jpg new file mode 100644 index 0000000..dd6e24a Binary files /dev/null and b/2025/assets/images/team/team02.jpg differ diff --git a/2025/assets/images/team/team03.jpg b/2025/assets/images/team/team03.jpg new file mode 100644 index 0000000..e6bc400 Binary files /dev/null and b/2025/assets/images/team/team03.jpg differ diff --git a/2025/assets/images/team/team04.jpg b/2025/assets/images/team/team04.jpg new file mode 100644 index 0000000..58432b8 Binary files /dev/null and b/2025/assets/images/team/team04.jpg differ diff --git a/2025/assets/images/team/team05.jpg b/2025/assets/images/team/team05.jpg new file mode 100644 index 0000000..08697db Binary files /dev/null and b/2025/assets/images/team/team05.jpg differ diff --git a/2025/assets/images/team/team06.jpg b/2025/assets/images/team/team06.jpg new file mode 100644 index 0000000..289a39b Binary files /dev/null and b/2025/assets/images/team/team06.jpg differ diff --git a/2025/assets/images/team/team07.jpg b/2025/assets/images/team/team07.jpg new file mode 100644 index 0000000..e95d76b Binary files /dev/null and b/2025/assets/images/team/team07.jpg differ diff --git a/2025/assets/images/team/team08.jpg b/2025/assets/images/team/team08.jpg new file mode 100644 index 0000000..7881e00 Binary files /dev/null and b/2025/assets/images/team/team08.jpg differ diff --git a/2025/assets/images/team/team09.jpg b/2025/assets/images/team/team09.jpg new file mode 100644 index 0000000..a3946b4 Binary files /dev/null and b/2025/assets/images/team/team09.jpg differ diff --git a/2025/assets/images/team/team10.jpg b/2025/assets/images/team/team10.jpg new file mode 100644 index 0000000..4831c92 Binary files /dev/null and b/2025/assets/images/team/team10.jpg differ diff --git a/2025/assets/images/team/team11.jpg b/2025/assets/images/team/team11.jpg new file mode 100644 index 0000000..305c62a Binary files /dev/null and b/2025/assets/images/team/team11.jpg differ diff --git a/2025/assets/images/team/team12.jpg b/2025/assets/images/team/team12.jpg new file mode 100644 index 0000000..ae08ad3 Binary files /dev/null and b/2025/assets/images/team/team12.jpg differ diff --git a/2025/assets/images/team/team13.jpg b/2025/assets/images/team/team13.jpg new file mode 100644 index 0000000..33cd939 Binary files /dev/null and b/2025/assets/images/team/team13.jpg differ diff --git a/2025/assets/js/common.js b/2025/assets/js/common.js new file mode 100644 index 0000000..a85ce66 --- /dev/null +++ b/2025/assets/js/common.js @@ -0,0 +1,352 @@ +// =========================================== +// COMMON SCRIPT FOR ALL PAGES +// ============================================ + +// =========================================== +// LOADER +// ============================================ + +function showLoader(text = 'Loading...') { + if (document.querySelector('.loader-overlay')) return; + + const body = document.querySelector("body"); + body.setAttribute("loading", ""); + + const loaderOverlay = document.createElement("div"); + loaderOverlay.classList.add("loader-overlay"); + loaderOverlay.innerHTML = ` + +
+
+
+
${text}
+ `; + body.appendChild(loaderOverlay); + + const progressBar = document.getElementById('loaderProgressBar'); + let progress = 0; + + const progressInterval = setInterval(() => { + progress += Math.random() * 10; + if (progress > 90) progress = 90; + if (progressBar) progressBar.style.width = progress + '%'; + }, 200); + + return { + interval: progressInterval, + element: loaderOverlay, + progressBar: progressBar + }; +} + +function hideLoader(loader) { + if (!loader || !loader.element) return; + + clearInterval(loader.interval); + if (loader.progressBar) loader.progressBar.style.width = '100%'; + + setTimeout(() => { + loader.element.classList.add('hidden'); + setTimeout(() => { + const body = document.querySelector("body"); + if (body && loader.element.parentNode === body) { + body.removeChild(loader.element); + } + body.removeAttribute("loading"); + }, 500); + }, 500); +} + + +// =========================================== +// DATA FETCHER +// ============================================ + +async function fetchData(url) { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + return await response.json(); +} + + +// =========================================== +// POPULATE FOOTER +// ============================================ + +function populateFooter(footerContent) { + const footer = document.querySelector('footer'); + if (!footer) return; + + footer.innerHTML = ''; + + const footerContentDiv = document.createElement('div'); + footerContentDiv.classList.add('footer-content'); + + const socialLinks = document.createElement('div'); + socialLinks.classList.add('social-links'); + + if (footerContent.social) { + footerContent.social.forEach((social) => { + const link = document.createElement('a'); + link.href = social.link; + link.textContent = social.name; + link.target = '_blank'; + link.rel = 'noopener noreferrer'; + link.classList.add('social-link'); + socialLinks.appendChild(link); + }); + } + + const copyright = document.createElement('p'); + copyright.classList.add('copyright'); + if (footerContent.copyright) { + copyright.innerHTML = footerContent.copyright.replace('{{YYYY}}', new Date().getFullYear()); + } + + footerContentDiv.appendChild(socialLinks); + footerContentDiv.appendChild(copyright); + footer.appendChild(footerContentDiv); +} + +// =========================================== +// MOBILE MENU +// ============================================ + +function initializeMobileMenu() { + const menuToggle = document.querySelector('.menu-toggle'); + const navLinks = document.querySelector('.nav-links'); + + if (menuToggle && navLinks) { + menuToggle.addEventListener('click', (e) => { + e.stopPropagation(); + navLinks.classList.toggle('active'); + menuToggle.classList.toggle('active'); + document.body.classList.toggle('menu-open'); + }); + + document.addEventListener('click', (e) => { + if (!navLinks.contains(e.target) && !menuToggle.contains(e.target)) { + navLinks.classList.remove('active'); + menuToggle.classList.remove('active'); + document.body.classList.remove('menu-open'); + } + }); + + window.addEventListener('scroll', () => { + if (navLinks.classList.contains('active')) { + navLinks.classList.remove('active'); + menuToggle.classList.remove('active'); + document.body.classList.remove('menu-open'); + } + }); + + // Handle menu item active states + const menuItems = navLinks.querySelectorAll('a'); + const currentPath = window.location.pathname; + const currentHash = window.location.hash; + + menuItems.forEach(item => { + // For regular page links + if (item.pathname === currentPath && !item.hash) { + item.classList.add('active'); + } + // For hash links on the same page + else if (currentPath === item.pathname && item.hash === currentHash && currentHash) { + item.classList.add('active'); + } + + item.addEventListener('click', () => { + // Only handle activation for hash links on the same page + if (item.pathname === window.location.pathname) { + menuItems.forEach(menuItem => { + if (menuItem.pathname === window.location.pathname) { + menuItem.classList.remove('active'); + } + }); + item.classList.add('active'); + } + }); + }); + } +} +// =========================================== +// NAVBAR SCROLL EFFECT +// ============================================ + +function initializeNavbarScroll() { + window.addEventListener('scroll', () => { + const navbar = document.getElementById('navbar'); + if (navbar && window.scrollY > 50) { + navbar.classList.add('scrolled'); + } else if (navbar) { + navbar.classList.remove('scrolled'); + } + }); +} + + +// =========================================== +// SMOOTH SCROLLING +// ============================================ + +function initializeSmoothScroll() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function (e) { + e.preventDefault(); + const targetId = this.getAttribute('href'); + + if (targetId === '#') return; + + const target = document.querySelector(targetId); + + if (target) { + const navbar = document.getElementById('navbar'); + const navHeight = navbar ? navbar.offsetHeight : 0; + const targetPosition = target.offsetTop - navHeight - 20; + + window.scrollTo({ + top: targetPosition, + behavior: 'smooth' + }); + } + }); + }); +} + +// =========================================== +// THEME TOGGLE FUNCTIONALITY (shared by all pages) +// ============================================ + +// Initialize theme ASAP to prevent flash of incorrect theme +(function() { + try { + const savedTheme = localStorage.getItem('theme'); + const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + const theme = savedTheme || (prefersDark ? 'dark' : 'light'); + document.documentElement.setAttribute('data-theme', theme); + } catch (_) { + // fail silently + } +})(); + +function initializeThemeToggle() { + const navLinks = document.querySelector('.nav-links'); + if (!navLinks) return; + + // Avoid duplicating the toggle if already added + if (document.getElementById('themeToggle')) return; + + const themeToggleItem = document.createElement('li'); + themeToggleItem.innerHTML = ` + + `; + navLinks.appendChild(themeToggleItem); + + const themeToggle = document.getElementById('themeToggle'); + const themeIcon = document.getElementById('themeIcon'); + const html = document.documentElement; + + // Set initial icon + const currentTheme = html.getAttribute('data-theme') || 'dark'; + themeIcon.textContent = currentTheme === 'dark' ? '🌙' : '☀️'; + + function setTheme(newTheme) { + html.setAttribute('data-theme', newTheme); + try { localStorage.setItem('theme', newTheme); } catch (_) {} + themeIcon.textContent = newTheme === 'dark' ? '🌙' : '☀️'; + window.dispatchEvent(new CustomEvent('themeChange', { detail: { theme: newTheme } })); + if (typeof trackEvent === 'function') { + try { trackEvent('Theme', 'Toggle', newTheme); } catch (_) {} + } + } + + function toggleTheme() { + const current = html.getAttribute('data-theme') || 'dark'; + const next = current === 'dark' ? 'light' : 'dark'; + setTheme(next); + } + + themeToggle.addEventListener('click', toggleTheme); + themeToggle.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + toggleTheme(); + } + }); + + // Listen for system theme changes if user hasn't set preference + if (window.matchMedia) { + const mq = window.matchMedia('(prefers-color-scheme: dark)'); + // Newer browsers support addEventListener on MediaQueryList + const mqListener = (e) => { + try { + if (!localStorage.getItem('theme')) { + setTheme(e.matches ? 'dark' : 'light'); + } + } catch (_) {} + }; + if (typeof mq.addEventListener === 'function') { + mq.addEventListener('change', mqListener); + } else if (typeof mq.addListener === 'function') { + mq.addListener(mqListener); + } + } + + // Sync theme across tabs + window.addEventListener('storage', (e) => { + if (e.key === 'theme' && e.newValue) { + html.setAttribute('data-theme', e.newValue); + themeIcon.textContent = e.newValue === 'dark' ? '🌙' : '☀️'; + } + }); +} + +// =========================================== +// INITIALIZE ALL COMMON FUNCTIONS +// ============================================ +document.addEventListener('DOMContentLoaded', () => { + initializeThemeToggle(); + initializeMobileMenu(); + initializeNavbarScroll(); + initializeSmoothScroll(); + + // Centralized Service Worker registration for all pages in /2025/ + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('service-worker.js?v19123215' ) + .then(registration => { + console.log('[SW] Registered with scope:', registration.scope); + + // Proactively check for updates + try { registration.update(); } catch (_) {} + + // Check again whenever tab becomes visible + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + try { registration.update(); } catch (_) {} + } + }); + + // Listen for new worker becoming active → reload page + registration.addEventListener('updatefound', () => { + const newWorker = registration.installing; + if (!newWorker) return; + + newWorker.addEventListener('statechange', () => { + if (newWorker.state === 'activated') { + console.log('[SW] New version activated → reloading...'); + window.location.reload(); + } + }); + }); + }) + .catch(err => console.warn('[SW] Registration failed:', err)); + }); + } +}); diff --git a/2025/assets/js/script.js b/2025/assets/js/script.js new file mode 100644 index 0000000..51c6f9f --- /dev/null +++ b/2025/assets/js/script.js @@ -0,0 +1,1286 @@ + + +// ============================================ +// UTILITY FUNCTIONS +// ============================================ + +// Debounce function for performance optimization +function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +// Throttle function for scroll events +function throttle(func, limit) { + let inThrottle; + return function(...args) { + if (!inThrottle) { + func.apply(this, args); + inThrottle = true; + setTimeout(() => inThrottle = false, limit); + } + }; +} + +// ============================================ +// SCROLL INDICATOR +// ============================================ + +// Show/hide scroll indicator based on scroll position +window.addEventListener('scroll', () => { + const indicator = document.querySelector('.scroll-indicator'); + if (!indicator) return; + + if (window.scrollY === 0) { + indicator.classList.remove('hide'); + } else { + indicator.classList.add('hide'); + } +}); + +// ============================================ +// ENHANCED LOADING STATE +// ============================================ + +document.addEventListener('DOMContentLoaded', async () => { + const loader = showLoader('Loading content...'); + + try { + const content = await fetchData("./assets/data/payload.json"); + + // Populate all sections + populateHero(content.hero); + populateAbout(content.about); + populateGallery(content.gallery); + populateWhyJDC(content.whyJdc); + populateSpeakers(content.speakers); + const previewSelector = content.sessionPreview || content.featuredSessions || []; + populateSessionPreview(content.sessions, previewSelector); + populateCountdown(content.countdown, content.hero); + populateSponsors(content.sponsors); + populateTeam(content.ourTeam); + populateLocation(content.location); + populateFooter(content.footer); + handleHashScroll(); + } catch (e) { + console.error(e.message); + if (loader && loader.element) { + const loaderText = loader.element.querySelector('.loader-text'); + if (loaderText) { + loaderText.textContent = 'Error loading content. Please refresh.'; + } + } + } finally { + hideLoader(loader); + initializeIntersectionObserver(); + initializeBackToTop(); + } +}); + +function handleHashScroll() { + if (window.location.hash) { + const target = document.querySelector(window.location.hash); + if (target) { + target.scrollIntoView({ behavior: 'smooth' }); + } + } +} + + +// ============================================ +// INTERSECTION OBSERVER FOR ANIMATIONS +// ============================================ + +function initializeIntersectionObserver() { + // Fallback: if IntersectionObserver is not supported, reveal all sections immediately + if (typeof window.IntersectionObserver !== 'function') { + document.querySelectorAll('section').forEach(section => { + section.classList.add('fade-in-section', 'visible'); + }); + return; + } + + // Be more permissive so elements reveal as user scrolls down + const observerOptions = { + threshold: 0, // trigger as soon as any pixel is visible + rootMargin: '0px 0px -20% 0px' // allow earlier trigger before fully in view + }; + + const observer = new IntersectionObserver((entries, obs) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + // Unobserve once visible to prevent repeated work + obs.unobserve(entry.target); + } + }); + }, observerOptions); + + // Observe all sections (including those without IDs, to avoid missing content) + document.querySelectorAll('section').forEach(section => { + section.classList.add('fade-in-section'); + observer.observe(section); + }); +} + +// ============================================ +// HERO SECTION +// ============================================ + +const populateHero = (heroContent) => { + const hero = document.getElementById("hero")?.querySelector('.hero-content'); + if (!hero) return; + hero.innerHTML = ''; + hero.setAttribute('role', 'banner'); + + const title = document.createElement("h1"); + title.classList.add('hero-title', 'glitch'); + title.innerHTML = heroContent.title; + + const subtitle = document.createElement("p"); + subtitle.classList.add('hero-subtitle'); + subtitle.innerHTML = heroContent.edition; + + // TODO: Enable link to register + // const cta = document.createElement("a"); + const cta = document.createElement("div"); + cta.classList.add('cta-button'); + cta.innerHTML = heroContent.cta.text; + // cta.setAttribute("href", heroContent.cta.link); + // cta.setAttribute("target", "_blank"); + // cta.setAttribute("rel", "noopener noreferrer"); + + hero.appendChild(title); + hero.appendChild(subtitle); + hero.appendChild(cta); +}; + +// ============================================ +// ABOUT SECTION +// ============================================ + +const populateAbout = (aboutContent) => { + const about = document.getElementById("about"); + if (!about) return; + about.innerHTML = ''; + + const aboutContentDiv = document.createElement("div"); + aboutContentDiv.classList.add("about-content"); + + const aboutText = document.createElement("div"); + aboutText.classList.add("about-text"); + + const sectionTag = document.createElement("span"); + sectionTag.classList.add('section-tag'); + sectionTag.innerHTML = "About the Event"; + + const title = document.createElement("h2"); + title.classList.add('section-title', 'gradient-text'); + title.innerHTML = aboutContent.title; + + const description = document.createElement("div"); + description.classList.add('about-description'); + description.innerHTML = aboutContent.description; + + aboutText.appendChild(sectionTag); + aboutText.appendChild(title); + aboutText.appendChild(description); + aboutContentDiv.appendChild(aboutText); + about.appendChild(aboutContentDiv); +}; + +// ============================================ +// GALLERY SECTION +// ============================================ + +const populateGallery = (galleryImages) => { + const gallerySection = document.getElementById('gallery'); + if (!gallerySection) return; + + gallerySection.innerHTML = ` + + + `; + + const track = gallerySection.querySelector('.carousel-track'); + const indicatorsContainer = gallerySection.querySelector('.carousel-indicators'); + + galleryImages.forEach((image, index) => { + // Create slide + const slide = document.createElement('li'); + slide.className = 'carousel-slide'; + if (index === 0) slide.classList.add('active'); + slide.innerHTML = `Gallery image ${index + 1}`; + track.appendChild(slide); + + // Create indicator + const indicator = document.createElement('button'); + indicator.className = 'carousel-indicator'; + if (index === 0) indicator.classList.add('active'); + indicator.setAttribute('aria-label', `Go to slide ${index + 1}`); + indicator.dataset.index = index; + indicatorsContainer.appendChild(indicator); + }); + + const slides = Array.from(track.children); + const indicators = Array.from(indicatorsContainer.children); + const nextButton = gallerySection.querySelector('.next'); + const prevButton = gallerySection.querySelector('.prev'); + const slideWidth = slides.length > 0 ? slides[0].getBoundingClientRect().width : 0; + + let currentIndex = 0; + let autoPlayInterval; + + const updateCarousel = (targetIndex) => { + if(slides.length === 0) return; + const currentSlide = slides[currentIndex]; + const targetSlide = slides[targetIndex]; + + // Move slides + track.style.transform = 'translateX(-' + targetSlide.style.left + ')'; + currentSlide.classList.remove('active'); + targetSlide.classList.add('active'); + + // Update indicators + indicators[currentIndex].classList.remove('active'); + indicators[targetIndex].classList.add('active'); + + currentIndex = targetIndex; + }; + + const setSlidePositions = () => { + if(slides.length === 0) return; + const currentSlideWidth = slides[0].getBoundingClientRect().width; + slides.forEach((slide, index) => { + slide.style.left = currentSlideWidth * index + 'px'; + }); + }; + + const nextSlide = () => { + if(slides.length === 0) return; + const nextIndex = (currentIndex + 1) % slides.length; + updateCarousel(nextIndex); + }; + + const prevSlide = () => { + if(slides.length === 0) return; + const prevIndex = (currentIndex - 1 + slides.length) % slides.length; + updateCarousel(prevIndex); + }; + + const startAutoPlay = () => { + stopAutoPlay(); // Prevent multiple intervals + autoPlayInterval = setInterval(nextSlide, 5000); + }; + + const stopAutoPlay = () => { + clearInterval(autoPlayInterval); + }; + + // Event Listeners + nextButton.addEventListener('click', () => { + stopAutoPlay(); + nextSlide(); + startAutoPlay(); + }); + + prevButton.addEventListener('click', () => { + stopAutoPlay(); + prevSlide(); + startAutoPlay(); + }); + + indicatorsContainer.addEventListener('click', e => { + const targetIndicator = e.target.closest('button'); + if (!targetIndicator) return; + + stopAutoPlay(); + const targetIndex = parseInt(targetIndicator.dataset.index, 10); + updateCarousel(targetIndex); + startAutoPlay(); + }); + + // Swipe support + let touchstartX = 0; + let touchendX = 0; + + track.addEventListener('touchstart', e => { + touchstartX = e.changedTouches[0].screenX; + stopAutoPlay(); + }, { passive: true }); + + track.addEventListener('touchend', e => { + touchendX = e.changedTouches[0].screenX; + if (touchendX < touchstartX - 50) nextSlide(); + if (touchendX > touchstartX + 50) prevSlide(); + startAutoPlay(); + }); + + // Initial setup + setSlidePositions(); + startAutoPlay(); + + // Recalculate on resize + window.addEventListener('resize', debounce(() => { + setSlidePositions(); + track.style.transition = 'none'; // Disable transition during resize adjustment + if(slides.length > 0){ + track.style.transform = 'translateX(-' + slides[currentIndex].style.left + ')'; + } + setTimeout(() => { + track.style.transition = ''; + }, 50); + }, 250)); +}; + + +// ============================================ +// WHY JDC SECTION +// ============================================ + +const populateWhyJDC = (whyJDC) => { + const whySection = document.getElementById("why-jdc"); + if (!whySection) return; + whySection.innerHTML = ''; + + const sectionTag = document.createElement('span'); + sectionTag.classList.add('section-tag'); + sectionTag.innerHTML = "Why Attend"; + whySection.appendChild(sectionTag); + + const title = document.createElement('h2'); + title.innerHTML = whyJDC.why.title; + title.classList.add('section-title', 'gradient-text'); + whySection.appendChild(title); + + const itemsGrid = document.createElement('div'); + itemsGrid.classList.add('why-grid'); + + whyJDC.why.items.forEach((item, index) => { + const card = document.createElement('div'); + card.classList.add('why-card'); + card.style.animationDelay = `${index * 0.1}s`; + + const itemTitle = document.createElement('h3'); + itemTitle.textContent = item.title; + itemTitle.classList.add('why-card-title'); + + const itemBody = document.createElement('p'); + itemBody.textContent = item.body; + itemBody.classList.add('why-card-body'); + + card.append(itemTitle, itemBody); + itemsGrid.appendChild(card); + }); + + whySection.appendChild(itemsGrid); +}; + +// ============================================ +// SPEAKERS SECTION WITH MODAL +// ============================================ + +const populateSpeakers = (speakers) => { + const speakersSection = document.getElementById('speakers'); + if (!speakersSection) return; + speakersSection.innerHTML = ''; + + const header = document.createElement('div'); + header.classList.add('speakers-header'); + + const sectionTag = document.createElement('span'); + sectionTag.classList.add('section-tag'); + sectionTag.innerHTML = "Featured Speakers"; + + const title = document.createElement('h2'); + title.innerHTML = "Learn from the Best"; + title.classList.add('section-title', 'gradient-text'); + + header.appendChild(sectionTag); + header.appendChild(title); + speakersSection.appendChild(header); + + const speakerGrid = document.createElement('div'); + speakerGrid.classList.add('speakers-grid'); + + createSpeakerModal(); + + speakers.forEach((speaker, idx) => { + const speakerCard = document.createElement('div'); + speakerCard.classList.add('speaker-card'); + speakerCard.setAttribute('tabindex', '0'); + speakerCard.setAttribute('role', 'button'); + speakerCard.setAttribute('aria-label', `View ${speaker.fullName}'s details`); + + speakerCard.innerHTML = ` + ${speaker.fullName} +
+

${speaker.fullName}

+

${speaker.company}

+
+ `; + + speakerCard.addEventListener('click', () => showSpeakerModal(speaker)); + speakerCard.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + showSpeakerModal(speaker); + } + }); + + speakerGrid.appendChild(speakerCard); + }); + + speakersSection.appendChild(speakerGrid); +}; + +// Create speaker modal structure +function createSpeakerModal() { + if (document.getElementById('speaker-modal-overlay')) return; + + const modalOverlay = document.createElement('div'); + modalOverlay.id = 'speaker-modal-overlay'; + modalOverlay.className = 'speaker-modal-overlay'; + modalOverlay.setAttribute('role', 'dialog'); + modalOverlay.setAttribute('aria-modal', 'true'); + modalOverlay.setAttribute('aria-labelledby', 'speaker-modal-name'); + + modalOverlay.innerHTML = ` +
+ +
+
+ +
+

+

+

+
+
+
+

Biography

+

+
+
+
+ `; + + document.body.appendChild(modalOverlay); + + // Close on overlay click + modalOverlay.addEventListener('click', (e) => { + if (e.target === modalOverlay) { + closeSpeakerModal(); + } + }); + + // Close button + const closeBtn = modalOverlay.querySelector('.speaker-modal-close'); + closeBtn.addEventListener('click', closeSpeakerModal); + + // ESC key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + closeSpeakerModal(); + } + }); +} + +// Show speaker modal +function showSpeakerModal(speaker) { + const modalOverlay = document.getElementById('speaker-modal-overlay'); + if (!modalOverlay) return; + + const previouslyFocused = document.activeElement; + + const modal = modalOverlay.querySelector('.speaker-modal'); + modal.querySelector('.speaker-modal-image').src = speaker.image; + modal.querySelector('.speaker-modal-image').alt = speaker.fullName; + modal.querySelector('.speaker-modal-name').textContent = speaker.fullName; + modal.querySelector('.speaker-modal-title').textContent = speaker.title || speaker.designation || 'Speaker'; + modal.querySelector('.speaker-modal-company').textContent = speaker.company; + modal.querySelector('.speaker-modal-bio p').innerHTML = speaker.bio || 'Biography coming soon...'; + + if (speaker.experience) { + detailsContainer.innerHTML += ` +
+
Experience
+
${speaker.experience}
+
+ `; + } + + if (speaker.expertise) { + detailsContainer.innerHTML += ` +
+
Expertise
+
${speaker.expertise}
+
+ `; + } + + if (speaker.sessionTopic) { + detailsContainer.innerHTML += ` +
+
Session Topic
+
${speaker.sessionTopic}
+
+ `; + } + + modalOverlay.classList.add('active'); + document.body.classList.add('modal-open'); + + modalOverlay.dataset.previousFocus = previouslyFocused; + setTimeout(() => { + modalOverlay.querySelector('.speaker-modal-close').focus(); + }, 100); +} + +// Close speaker modal +function closeSpeakerModal() { + const modalOverlay = document.getElementById('speaker-modal-overlay'); + if (modalOverlay) { + modalOverlay.classList.remove('active'); + document.body.classList.remove('modal-open'); + + const previousFocus = modalOverlay.dataset.previousFocus; + if (previousFocus) { + previousFocus.focus(); + } + } +} + +// Mobile swipe to close modal +let touchStartY = 0; +let touchEndY = 0; + +document.addEventListener('touchstart', (e) => { + const modal = document.querySelector('.speaker-modal'); + if (modal && modal.contains(e.target)) { + touchStartY = e.changedTouches[0].screenY; + } +}); + +document.addEventListener('touchend', (e) => { + const modal = document.querySelector('.speaker-modal'); + if (modal && modal.contains(e.target)) { + touchEndY = e.changedTouches[0].screenY; + if (touchEndY - touchStartY > 100) { + closeSpeakerModal(); + } + } +}); + +// ============================================ +// TEAM SECTION +// ============================================ + +const populateTeam = (teamMembers) => { + const teamSection = document.getElementById('our-team'); + if (!teamSection) return; + teamSection.innerHTML = ''; + + const header = document.createElement('div'); + header.classList.add('speakers-header'); + + const sectionTag = document.createElement('span'); + sectionTag.classList.add('section-tag'); + sectionTag.innerHTML = "Our Team"; + + const title = document.createElement('h2'); + title.innerHTML = "Meet the Organizers"; + title.classList.add('section-title', 'gradient-text'); + + header.appendChild(sectionTag); + header.appendChild(title); + teamSection.appendChild(header); + + const teamGrid = document.createElement('div'); + teamGrid.classList.add('speakers-grid'); + + teamMembers.forEach(member => { + const teamCard = document.createElement('div'); + teamCard.classList.add('speaker-card'); + + teamCard.innerHTML = ` + ${member.fullName} +
+

${member.fullName}

+

${member.company}

+
+ `; + + teamGrid.appendChild(teamCard); + }); + + teamSection.appendChild(teamGrid); +}; + +// ============================================ +// SPONSORS SECTION +// ============================================ + +const populateSponsors = (sponsors) => { + const sponsorsSection = document.getElementById('sponsors'); + if (!sponsorsSection || !sponsors) return; + sponsorsSection.innerHTML = ''; + + const header = document.createElement('div'); + header.classList.add('sponsors-header'); + + const sectionTag = document.createElement('span'); + sectionTag.classList.add('section-tag'); + sectionTag.innerHTML = "Partners & Sponsors"; + + const subtitle = document.createElement('h2'); + const title = document.createElement('h1'); + subtitle.innerHTML = "Fueling the Future of Java"; + title.innerHTML = "This year our proud sponsor"; + subtitle.classList.add('section-subtitle'); + title.classList.add('section-title', 'gradient-text'); + + header.appendChild(sectionTag); + header.appendChild(subtitle); + header.appendChild(title); + sponsorsSection.appendChild(header); + + const sponsorGrid = document.createElement('div'); + sponsorGrid.classList.add('sponsors-grid'); + + sponsors.forEach(sponsor => { + const sponsorCard = document.createElement('a'); + sponsorCard.classList.add('sponsor-card'); + sponsorCard.href = sponsor.website; + sponsorCard.target = '_blank'; + sponsorCard.rel = 'noopener noreferrer'; + sponsorCard.setAttribute('aria-label', `Visit ${sponsor.name}`); + + sponsorCard.innerHTML = ` + + `; + + sponsorGrid.appendChild(sponsorCard); + }); + + sponsorsSection.appendChild(sponsorGrid); +}; + + +// ============================================ +// COUNTDOWN SECTION +// ============================================ + +const populateCountdown = (cdC) => { + const countdown = document.getElementById('countdown'); + if (!countdown) return; + countdown.innerHTML = ''; + + const countdownContent = document.createElement('div'); + countdownContent.classList.add('countdown-content'); + + const title = document.createElement('h2'); + title.classList.add('countdown-title', 'gradient-text'); + title.innerHTML = cdC.title.replace('\n', '
'); + + const timerContainer = document.createElement('div'); + timerContainer.classList.add('timer-container'); + + timerContainer.innerHTML = ` +
+ 00 + Days +
+
+ 00 + Hours +
+
+ 00 + Minutes +
+
+ 00 + Seconds +
+ `; + + const eventDate = document.createElement('p'); + eventDate.classList.add('event-date'); + eventDate.innerHTML = cdC.subsection.date; + + const ctaButton = document.createElement('a'); + ctaButton.classList.add('cta-button'); + ctaButton.href = cdC.subsection.link.url; + ctaButton.target = '_blank'; + ctaButton.rel = 'noopener noreferrer'; + ctaButton.innerHTML = cdC.subsection.link.text; + + countdownContent.appendChild(title); + countdownContent.appendChild(timerContainer); + countdownContent.appendChild(eventDate); + countdownContent.appendChild(ctaButton); + countdown.appendChild(countdownContent); + + const targetDate = new Date(cdC.targetDate).getTime(); + + const timerInterval = setInterval(() => { + const now = new Date().getTime(); + const timeLeft = targetDate - now; + + if (timeLeft < 0) { + clearInterval(timerInterval); + document.getElementById('days').textContent = '00'; + document.getElementById('hours').textContent = '00'; + document.getElementById('minutes').textContent = '00'; + document.getElementById('seconds').textContent = '00'; + return; + } + + const days = Math.floor(timeLeft / (1000 * 60 * 60 * 24)); + const hours = Math.floor((timeLeft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000); + + document.getElementById('days').textContent = days.toString().padStart(2, '0'); + document.getElementById('hours').textContent = hours.toString().padStart(2, '0'); + document.getElementById('minutes').textContent = minutes.toString().padStart(2, '0'); + document.getElementById('seconds').textContent = seconds.toString().padStart(2, '0'); + }, 1000); +}; + +// ============================================ +// VENUE/LOCATION SECTION +// ============================================ + +const populateLocation = (location) => { + const venue = document.getElementById('venue'); + if (!venue) return; + venue.innerHTML = ''; + + const venueContent = document.createElement('div'); + venueContent.classList.add('venue-content'); + + const venueInfo = document.createElement('div'); + venueInfo.classList.add('venue-info'); + + const sectionTag = document.createElement('span'); + sectionTag.classList.add('section-tag'); + sectionTag.textContent = "Event Venue"; + venueInfo.appendChild(sectionTag); + + const title = document.createElement('h2'); + title.classList.add('section-title', 'gradient-text'); + title.textContent = location.title; + venueInfo.appendChild(title); + + const description = document.createElement('p'); + description.classList.add('about-description'); + description.textContent = location.description; + venueInfo.appendChild(description); + + const addressCard = document.createElement('div'); + addressCard.classList.add('address-card'); + + addressCard.innerHTML = ` +

Conference Center

+

📍 ${location.address?.name || 'N/A'}

+

🏢 ${location.address?.street || ''}

+

🌆 ${location.address?.city || ''}

+

📧 ${location.email}

+ `; + venueInfo.appendChild(addressCard); + + const venueMap = document.createElement('div'); + venueMap.classList.add('venue-map'); + venueMap.innerHTML = location.mapEmbed; + + venueContent.appendChild(venueMap); + venueContent.appendChild(venueInfo); + venue.appendChild(venueContent); +}; + +// ============================================ +// SESSION SECTION POPULATION +// ============================================ + +const populateSessionPreview = (sessionsData, previewList = []) => { + const sessionSection = document.getElementById('session'); + if (!sessionSection) return; + + sessionSection.innerHTML = ''; + + const header = document.createElement('div'); + header.classList.add('session-preview-header'); + header.innerHTML = ` + Conference Sessions +

Featured Sessions

+

+ Get a glimpse of the exciting talks we have lined up for JDC 2025. +

+ `; + sessionSection.appendChild(header); + + const previewGrid = document.createElement('div'); + previewGrid.classList.add('session-preview-grid'); + + // Resolve which sessions to feature based on optional previewList + const normalized = Array.isArray(previewList) ? previewList : []; + const byTitle = new Map(); + sessionsData.forEach((s, i) => byTitle.set((s.title || '').trim().toLowerCase(), i)); + const picked = []; + const usedIdx = new Set(); + + // Helper to add by index if valid + const addByIndex = (idx) => { + if (typeof idx !== 'number') return; + if (idx < 0 || idx >= sessionsData.length) return; + if (usedIdx.has(idx)) return; + usedIdx.add(idx); + picked.push(sessionsData[idx]); + }; + + // 1) Try to resolve user-specified list (string title, number index, or {title|index}) + normalized.forEach(item => { + if (typeof item === 'number') { + addByIndex(item); + return; + } + if (typeof item === 'string') { + const key = item.trim().toLowerCase(); + const idx = byTitle.get(key); + if (idx !== undefined) addByIndex(idx); + return; + } + if (item && typeof item === 'object') { + if (typeof item.index === 'number') { + addByIndex(item.index); + return; + } + if (typeof item.title === 'string') { + const key = item.title.trim().toLowerCase(); + const idx = byTitle.get(key); + if (idx !== undefined) addByIndex(idx); + } + } + }); + + // 2) Fallback: fill remaining slots (up to 2) from the start, skipping duplicates + const MAX_CARDS = 2; + for (let i = 0; picked.length < MAX_CARDS && i < sessionsData.length; i++) { + if (!usedIdx.has(i)) addByIndex(i); + } + + const featuredSessions = picked.slice(0, MAX_CARDS); + + featuredSessions.forEach((session, index) => { + const card = document.createElement('div'); + card.classList.add('session-preview-card'); + card.style.animationDelay = `${index * 0.1}s`; + + card.innerHTML = ` +
${session.track}
+
+ ${session.time} + ${session.duration} +
+

${session.title}

+

${session.abstract.replace(/<[^>]*>/g, '').substring(0, 150)}... See more

+
+ ${session.speaker.name} +
+
${session.speaker.name}
+
${session.speaker.role}
+
+
+ `; + + previewGrid.appendChild(card); + }); + + sessionSection.appendChild(previewGrid); + + const ctaContainer = document.createElement('div'); + ctaContainer.classList.add('session-preview-cta'); + ctaContainer.innerHTML = ` + + View All Sessions + + +

Explore ${sessionsData.length - 2} more sessions from industry experts

+ `; + sessionSection.appendChild(ctaContainer); +}; + +// ============================================ +// PARALLAX EFFECT ON HERO (Optimized) +// ============================================ + +let ticking = false; + +const handleParallax = () => { + const scrolled = window.pageYOffset; + const heroContent = document.querySelector('.hero-content'); + + if (heroContent && scrolled < window.innerHeight) { + heroContent.style.transform = `translateY(${scrolled * 0.5}px)`; + heroContent.style.opacity = Math.max(0, 1 - scrolled / 800); + } + + ticking = false; +}; + +window.addEventListener('scroll', () => { + if (!ticking) { + window.requestAnimationFrame(handleParallax); + ticking = true; + } +}); + +// ============================================ +// DYNAMIC BACKGROUND ORBS (Optimized) +// ============================================ + +let orbTicking = false; + +const handleOrbMovement = (e) => { + const orb1 = document.querySelector('.orb1'); + const orb2 = document.querySelector('.orb2'); + + if (!orb1 || !orb2) return; + + const moveX = (e.clientX - window.innerWidth / 2) * 0.01; + const moveY = (e.clientY - window.innerHeight / 2) * 0.01; + + orb1.style.transform = `translate(${moveX}px, ${moveY}px)`; + orb2.style.transform = `translate(${-moveX}px, ${-moveY}px)`; + + orbTicking = false; +}; + +document.addEventListener('mousemove', (e) => { + if (!orbTicking) { + window.requestAnimationFrame(() => handleOrbMovement(e)); + orbTicking = true; + } +}); + +// ============================================ +// CTA BUTTON RIPPLE EFFECT +// ============================================ + +document.addEventListener('DOMContentLoaded', () => { + setTimeout(() => { + const ctaButtons = document.querySelectorAll('.cta-button'); + + ctaButtons.forEach(button => { + button.addEventListener('mouseenter', function(e) { + const ripple = document.createElement('span'); + ripple.style.position = 'absolute'; + ripple.style.borderRadius = '50%'; + ripple.style.background = 'rgba(255,255,255,0.5)'; + ripple.style.width = ripple.style.height = '0'; + ripple.style.top = '50%'; + ripple.style.left = '50%'; + ripple.style.transform = 'translate(-50%, -50%)'; + ripple.style.pointerEvents = 'none'; + this.appendChild(ripple); + + setTimeout(() => { + ripple.style.width = ripple.style.height = '200px'; + ripple.style.opacity = '0'; + ripple.style.transition = 'all 0.5s ease'; + }, 10); + + setTimeout(() => { + ripple.remove(); + }, 500); + }); + }); + }, 1000); +}); + +// ============================================ +// BACK TO TOP BUTTON +// ============================================ + +function initializeBackToTop() { + // Create back to top button + const backToTopBtn = document.createElement('button'); + backToTopBtn.className = 'back-to-top'; + backToTopBtn.id = 'backToTop'; + backToTopBtn.setAttribute('aria-label', 'Back to top'); + backToTopBtn.innerHTML = '↑'; + document.body.appendChild(backToTopBtn); + + // Show/hide button on scroll + const handleBackToTopScroll = throttle(() => { + if (window.pageYOffset > 300) { + backToTopBtn.classList.add('visible'); + } else { + backToTopBtn.classList.remove('visible'); + } + }, 100); + + window.addEventListener('scroll', handleBackToTopScroll); + + // Scroll to top on click + backToTopBtn.addEventListener('click', () => { + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + }); + + // Keyboard accessibility + backToTopBtn.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + } + }); +} + + +// ============================================ +// CARD INTERACTIONS (for Why JDC cards) +// ============================================ + +document.addEventListener('DOMContentLoaded', () => { + setTimeout(() => { + // Limit interactive card effects to .why-card only; remove tilt from .speaker-card (speakers and our-team) + const cards = document.querySelectorAll('.why-card'); + + cards.forEach(card => { + // Ripple effect on click + card.addEventListener('click', function(e) { + // Skip if it's already a speaker card (has its own click handler) + if (this.classList.contains('speaker-card')) return; + + const ripple = document.createElement('span'); + ripple.classList.add('card-ripple'); + + const rect = this.getBoundingClientRect(); + const size = Math.max(rect.width, rect.height); + const x = e.clientX - rect.left - size / 2; + const y = e.clientY - rect.top - size / 2; + + ripple.style.cssText = ` + position: absolute; + border-radius: 50%; + background: rgba(255, 255, 255, 0.3); + width: ${size}px; + height: ${size}px; + left: ${x}px; + top: ${y}px; + transform: scale(0); + animation: ripple-animation 0.6s ease-out; + pointer-events: none; + `; + + this.appendChild(ripple); + + setTimeout(() => ripple.remove(), 600); + }); + + // 3D tilt effect on mouse move + card.addEventListener('mousemove', function(e) { + const rect = this.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + const centerX = rect.width / 2; + const centerY = rect.height / 2; + + const rotateX = (y - centerY) / 20; + const rotateY = (centerX - x) / 20; + + this.style.transform = ` + translateY(-10px) + perspective(1000px) + rotateX(${rotateX}deg) + rotateY(${rotateY}deg) + `; + }); + + card.addEventListener('mouseleave', function() { + this.style.transform = ''; + }); + }); + }, 1000); +}); + +// ============================================ +// IMAGE LAZY LOADING FALLBACK (for older browsers) +// ============================================ + +if ('IntersectionObserver' in window) { + const imageObserver = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + if (img.dataset.src) { + img.src = img.dataset.src; + img.removeAttribute('data-src'); + } + observer.unobserve(img); + } + }); + }); + + document.addEventListener('DOMContentLoaded', () => { + setTimeout(() => { + const lazyImages = document.querySelectorAll('img[data-src]'); + lazyImages.forEach(img => imageObserver.observe(img)); + }, 1000); + }); +} + +// ============================================ +// SMOOTH REVEAL ANIMATIONS +// ============================================ + +function addRevealAnimations() { + const elements = document.querySelectorAll('.speaker-card, .why-card, .timer-block'); + + elements.forEach((el, index) => { + el.style.opacity = '0'; + el.style.transform = 'translateY(20px)'; + el.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; + + setTimeout(() => { + el.style.opacity = '1'; + el.style.transform = 'translateY(0)'; + }, index * 100); + }); +} + +// ============================================ +// ERROR HANDLING FOR IMAGES +// ============================================ + +document.addEventListener('DOMContentLoaded', () => { + setTimeout(() => { + const images = document.querySelectorAll('img'); + + images.forEach(img => { + img.addEventListener('error', function() { + // Create a placeholder if image fails to load + this.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + this.style.display = 'flex'; + this.style.alignItems = 'center'; + this.style.justifyContent = 'center'; + this.alt = 'Image not available'; + }); + }); + }, 1000); +}); + + + +// ============================================ +// ENHANCED FOCUS INDICATORS +// ============================================ + +document.addEventListener('DOMContentLoaded', () => { + let isUsingKeyboard = false; + + document.addEventListener('keydown', (e) => { + if (e.key === 'Tab') { + isUsingKeyboard = true; + document.body.classList.add('keyboard-nav'); + } + }); + + document.addEventListener('mousedown', () => { + isUsingKeyboard = false; + document.body.classList.remove('keyboard-nav'); + }); +}); + + + +// ============================================ +// REDUCE MOTION FOR ACCESSIBILITY +// ============================================ + +const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + +if (prefersReducedMotion.matches) { + // Disable animations + document.documentElement.style.setProperty('--animation-duration', '0.01ms'); + + // Remove auto-slide from carousel + const carouselTrack = document.querySelector('.modern-carousel-track'); + if (carouselTrack) { + carouselTrack.style.animation = 'none'; + } +} + +// ============================================ +// VIEWPORT HEIGHT FIX FOR MOBILE +// ============================================ + +function setVH() { + const vh = window.innerHeight * 0.01; + document.documentElement.style.setProperty('--vh', `${vh}px`); +} + +window.addEventListener('resize', debounce(setVH, 250)); +setVH(); + +// ============================================ +// NETWORK STATUS INDICATOR +// ============================================ + +function handleNetworkChange() { + if (!navigator.onLine) { + const offlineNotice = document.createElement('div'); + offlineNotice.id = 'offline-notice'; + offlineNotice.style.cssText = ` + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + background: #ff6b6b; + color: white; + padding: 12px 24px; + border-radius: 50px; + z-index: 10000; + font-size: 0.9rem; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); + `; + offlineNotice.textContent = 'You are offline. Some features may not work.'; + document.body.appendChild(offlineNotice); + } else { + const notice = document.getElementById('offline-notice'); + if (notice) notice.remove(); + } +} + +window.addEventListener('online', handleNetworkChange); +window.addEventListener('offline', handleNetworkChange); + +console.log('✅ JDC 2025 Website Initialized Successfully'); diff --git a/2025/assets/js/sessions.js b/2025/assets/js/sessions.js new file mode 100644 index 0000000..7556b87 --- /dev/null +++ b/2025/assets/js/sessions.js @@ -0,0 +1,332 @@ + +// ============================================ +// SESSIONS PAGE SCRIPT +// ============================================ + +document.addEventListener('DOMContentLoaded', async () => { + const loader = showLoader('Loading sessions...'); + + try { + const content = await fetchData("./assets/data/payload.json"); + + // Build a lookup map for speakers by fullName and by slug name (if provided) + const speakers = Array.isArray(content.speakers) ? content.speakers : []; + const speakerMap = new Map(); + speakers.forEach(sp => { + if (sp.fullName) speakerMap.set(sp.fullName.trim().toLowerCase(), sp); + if (sp.name) speakerMap.set(sp.name.trim().toLowerCase(), sp); + }); + + // Ensure modal structure exists for this page + createSpeakerModal(); + + // Populate sessions + if (content.sessions) { + populateSessions(content.sessions, speakerMap); + } + + // Populate footer + if (content.footer) { + populateFooter(content.footer); + } + + } catch (e) { + console.error(e.message); + if (loader && loader.element) { + const loaderText = loader.element.querySelector('.loader-text'); + if (loaderText) { + loaderText.textContent = 'Error loading sessions. Please try again later.'; + } + } + } finally { + hideLoader(loader); + } +}); + +// ============================================ +// POPULATE SESSIONS +// ============================================ + +function populateSessions(sessionsData, speakerMap) { + const grid = document.getElementById('sessionsGrid'); + if (!grid) return; + + grid.innerHTML = ''; + + + sessionsData.forEach((session, index) => { + const card = document.createElement('div'); + card.classList.add('session-card'); + card.dataset.track = session.track; + card.style.animationDelay = `${index * 0.1}s`; + + const speakerName = session.speaker?.name || ''; + + card.innerHTML = ` +
+
+ ${session.time} + ${session.duration} +
+
+ ${session.track} +

${session.title}

+
${session.abstract}
+ + +
+ ${speakerName} +
+
${speakerName}
+
${session.speaker.role || ''}
+
+
+ +
+ ${session.tags.map(tag => `${tag}`).join('')} +
+
+
+ `; + + grid.appendChild(card); + }); + + initializeSessionInteractions(sessionsData, speakerMap); +} + +// ============================================ +// SPEAKER MODAL (sessions page local implementation) +// ============================================ + +function createSpeakerModal() { + if (document.getElementById('speaker-modal-overlay')) return; + const modalOverlay = document.createElement('div'); + modalOverlay.id = 'speaker-modal-overlay'; + modalOverlay.className = 'speaker-modal-overlay'; + modalOverlay.setAttribute('role', 'dialog'); + modalOverlay.setAttribute('aria-modal', 'true'); + modalOverlay.setAttribute('aria-labelledby', 'speaker-modal-name'); + modalOverlay.innerHTML = ` +
+ +
+
+ +
+

+

+

+
+
+
+

Biography

+

+
+
+
`; + document.body.appendChild(modalOverlay); + + // overlay click to close + modalOverlay.addEventListener('click', (e) => { + if (e.target === modalOverlay) closeSpeakerModal(); + }); + // close button + const closeBtn = modalOverlay.querySelector('.speaker-modal-close'); + if (closeBtn) closeBtn.addEventListener('click', closeSpeakerModal); + // esc + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') closeSpeakerModal(); + }); +} + +function showSpeakerModal(speaker) { + const modalOverlay = document.getElementById('speaker-modal-overlay'); + if (!modalOverlay) return; + + const modal = modalOverlay.querySelector('.speaker-modal'); + const img = modal.querySelector('.speaker-modal-image'); + const nameEl = modal.querySelector('.speaker-modal-name'); + const titleEl = modal.querySelector('.speaker-modal-title'); + const companyEl = modal.querySelector('.speaker-modal-company'); + const bioEl = modal.querySelector('.speaker-modal-bio p'); + + if (img) { + img.src = speaker.image || ''; + img.alt = speaker.fullName || speaker.name || 'Speaker'; + } + if (nameEl) nameEl.textContent = speaker.fullName || speaker.name || 'Speaker'; + if (titleEl) titleEl.textContent = speaker.title || speaker.designation || ''; + if (companyEl) companyEl.textContent = speaker.company || ''; + if (bioEl) bioEl.innerHTML = speaker.bio || 'Biography coming soon...'; + + modalOverlay.classList.add('active'); + const closeBtn = modalOverlay.querySelector('.speaker-modal-close'); + if (closeBtn) closeBtn.focus(); +} + +function closeSpeakerModal() { + const modalOverlay = document.getElementById('speaker-modal-overlay'); + if (!modalOverlay) return; + modalOverlay.classList.remove('active'); +} + +// ============================================ +// SESSION INTERACTIONS +// ============================================ + +function initializeSessionInteractions(sessionsData, speakerMap) { + const filterButtons = document.querySelectorAll('.filter-btn'); + const sessionCards = document.querySelectorAll('.session-card'); + const emptyState = document.getElementById('emptyState'); + + // Filter functionality + filterButtons.forEach(button => { + button.addEventListener('click', () => { + const filter = button.dataset.filter; + + filterButtons.forEach(btn => btn.classList.remove('active')); + button.classList.add('active'); + + let visibleCount = 0; + sessionCards.forEach((card, index) => { + const track = card.dataset.track; + + if (filter === 'all' || track === filter) { + card.style.display = 'block'; + card.style.animation = 'none'; + setTimeout(() => { + card.style.animationDelay = `${index * 0.1}s`; + card.style.animation = 'fadeInUp 0.6s ease forwards'; + }, 10); + visibleCount++; + } else { + card.style.display = 'none'; + } + }); + + // Show/hide empty state + if (emptyState) { + emptyState.style.display = visibleCount === 0 ? 'block' : 'none'; + } + }); + }); + + // SEE MORE/LESS for abstracts + const setupReadMore = () => { + document.querySelectorAll('.session-card').forEach(card => { + const abstract = card.querySelector('.session-abstract'); + const btn = card.querySelector('.read-more'); + if (!abstract || !btn) return; + + // Determine if content overflows (i.e., is clamped) + const needsToggle = abstract.scrollHeight > abstract.clientHeight + 1; // allow small rounding diff + btn.style.display = needsToggle ? 'inline-flex' : 'none'; + + // Reset collapsed state if not needed + if (!needsToggle) { + card.classList.remove('expanded'); + btn.setAttribute('aria-expanded', 'false'); + btn.textContent = 'See more'; + } + + // Attach click handler once + if (!btn._bound) { + btn.addEventListener('click', (e) => { + const expanded = card.classList.toggle('expanded'); + btn.textContent = expanded ? 'See less' : 'See more'; + btn.setAttribute('aria-expanded', String(expanded)); + }); + btn._bound = true; + } + }); + }; + + // Initial setup + setupReadMore(); + + // Re-evaluate on window resize (simple debounce) + let _rmTimer; + window.addEventListener('resize', () => { + clearTimeout(_rmTimer); + _rmTimer = setTimeout(setupReadMore, 150); + }); + + // Speaker click functionality + document.querySelectorAll('.session-speaker').forEach(speakerElement => { + const activate = () => { + const clickEvent = new Event('click', { bubbles: true }); + speakerElement.dispatchEvent(clickEvent); + }; + // Keyboard accessibility: Enter/Space activates + speakerElement.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + activate(); + } + }); + + // Click opens modal (existing listener below) + speakerElement.addEventListener('click', (e) => { + e.stopPropagation(); // Prevent card from toggling if that functionality is re-added + const speakerNameRaw = speakerElement.dataset.speakerName || ''; + const speakerName = speakerNameRaw.trim().toLowerCase(); + + // 1) Prefer bio provided directly in the session payload + const bioEncoded = speakerElement.dataset.speakerBio || ''; + const bioFromSession = bioEncoded ? decodeURIComponent(bioEncoded) : ''; + if (bioFromSession && bioFromSession.trim().length > 0) { + const modalSpeaker = { + fullName: speakerElement.querySelector('.speaker-name')?.textContent || speakerNameRaw || 'Speaker', + name: speakerNameRaw, + image: speakerElement.querySelector('img')?.getAttribute('src') || '', + title: speakerElement.querySelector('.speaker-role')?.textContent || '', + company: '', + bio: bioFromSession + }; + if (typeof showSpeakerModal === 'function') { + showSpeakerModal(modalSpeaker); + } else if (typeof window.showSpeakerModal === 'function') { + window.showSpeakerModal(modalSpeaker); + } + return; // Do not fallback if session bio is present + } + + // 2) Fallback: try to find a full speaker object with bio from the global map + let fullSpeaker = speakerMap && speakerMap.get(speakerName); + + // Fallback: attempt to match by full name in sessionsData if not found by key + if (!fullSpeaker) { + const session = Array.from(sessionsData).find(s => (s.speaker?.name || '').trim().toLowerCase() === speakerName); + const guessName = session?.speaker?.name?.trim().toLowerCase(); + if (guessName && speakerMap) fullSpeaker = speakerMap.get(guessName); + } + + if (fullSpeaker) { + // Ensure required fields expected by showSpeakerModal + const modalSpeaker = { + ...fullSpeaker, + fullName: fullSpeaker.fullName || fullSpeaker.name || (speakerElement.querySelector('.speaker-name')?.textContent) || 'Speaker', + }; + if (typeof showSpeakerModal === 'function') { + showSpeakerModal(modalSpeaker); + } else if (typeof window.showSpeakerModal === 'function') { + window.showSpeakerModal(modalSpeaker); + } + } else { + console.warn('Speaker bio not found for:', speakerName); + // As a graceful fallback, open minimal modal from the card speaker data + const fallback = { + fullName: speakerElement.querySelector('.speaker-name')?.textContent || 'Speaker', + image: speakerElement.querySelector('img')?.getAttribute('src') || '', + title: speakerElement.querySelector('.speaker-role')?.textContent || '', + company: '', + bio: 'Biography will be available soon.' + }; + if (typeof showSpeakerModal === 'function') { + showSpeakerModal(fallback); + } + } + }); + }); +} diff --git a/2024/generate-manifest.js b/2025/generate-manifest.js similarity index 80% rename from 2024/generate-manifest.js rename to 2025/generate-manifest.js index f91aaa8..c97bf4a 100644 --- a/2024/generate-manifest.js +++ b/2025/generate-manifest.js @@ -3,12 +3,16 @@ const path = require('path'); const directory = './'; // Root directory to scan const manifestFile = 'manifest.json'; -const allowedExtensions = ['.html', '.css', '.js', '.png', '.jpg', '.jpeg', '.svg', '.webp']; // File types to include +const allowedExtensions = ['.html', '.css', '.js', '.png', '.jpg', '.jpeg', '.svg', '.webp', '.ico']; // File types to include const scanDirectory = (dir) => { let files = []; fs.readdirSync(dir).forEach(file => { const fullPath = path.join(dir, file); + if (fullPath.includes('service-worker.js') || fullPath.includes('manifest.json')) { + // Don't include service worker in the manifest.json + return; + } if (fs.statSync(fullPath).isDirectory()) { files = files.concat(scanDirectory(fullPath)); // Recursive call for subdirectories } else if (allowedExtensions.includes(path.extname(fullPath))) { diff --git a/2025/index.html b/2025/index.html new file mode 100644 index 0000000..d8a512c --- /dev/null +++ b/2025/index.html @@ -0,0 +1,75 @@ + + + + + + Java Developers' Conference 2025 + + + + + + +
+
+
+
+ + + +
+
+
+
+
+ +
+
+ + + +
+
+ + +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + diff --git a/2025/manifest.json b/2025/manifest.json new file mode 100644 index 0000000..14e8e45 --- /dev/null +++ b/2025/manifest.json @@ -0,0 +1,66 @@ +{ + "assets": [ + "assets/css/sessions.css", + "assets/css/styles.css", + "assets/icons/android-chrome-192x192.png", + "assets/icons/favicon-16x16.png", + "assets/icons/favicon-32x32.png", + "assets/icons/favicon.ico", + "assets/images/gallery/00-slider.jpg", + "assets/images/gallery/01-slider.jpg", + "assets/images/gallery/02-slider.jpg", + "assets/images/gallery/03-slider.jpg", + "assets/images/gallery/04-slider.jpg", + "assets/images/gallery/05-slider.jpg", + "assets/images/gallery/06-slider.jpg", + "assets/images/gallery/07-slider.jpg", + "assets/images/gallery/08-slider.jpg", + "assets/images/gallery/09-slider.jpg", + "assets/images/gallery/10-slider.jpg", + "assets/images/gallery/11-slider.jpg", + "assets/images/gallery/12-slider..jpg", + "assets/images/gallery/13-slider..jpg", + "assets/images/gallery/14-slider..jpg", + "assets/images/speakers/RezaRahman.png", + "assets/images/speakers/abir.jpeg", + "assets/images/speakers/anik.jpeg", + "assets/images/speakers/avatar.png", + "assets/images/speakers/habib.jpg", + "assets/images/speakers/habib.png", + "assets/images/speakers/hasanat.jpg", + "assets/images/speakers/kasim.jpg", + "assets/images/speakers/khaled.jpg", + "assets/images/speakers/manna.jpg", + "assets/images/speakers/minhaj.jpeg", + "assets/images/speakers/moz.jpg", + "assets/images/speakers/oronno.png", + "assets/images/speakers/rakibul.jpg", + "assets/images/speakers/rokon.png", + "assets/images/speakers/shaaf.jpg", + "assets/images/speakers/taemoon.jpg", + "assets/images/speakers/zahur.jpg", + "assets/images/sponsor/dsi-logo.svg", + "assets/images/team/team01.jpg", + "assets/images/team/team02.jpg", + "assets/images/team/team03.jpg", + "assets/images/team/team04.jpg", + "assets/images/team/team05.jpg", + "assets/images/team/team06.jpg", + "assets/images/team/team07.jpg", + "assets/images/team/team08.jpg", + "assets/images/team/team09.jpg", + "assets/images/team/team10.jpg", + "assets/images/team/team11.jpg", + "assets/images/team/team12.jpg", + "assets/images/team/team13.jpg", + "assets/js/common.js", + "assets/js/script.js", + "assets/js/sessions.js", + "assets/css/schedule.css", + "assets/data/payload.json", + "generate-manifest.js", + "index.html", + "sessions.html", + "schedule/index.html" + ] +} \ No newline at end of file diff --git a/2025/schedule/index.html b/2025/schedule/index.html new file mode 100644 index 0000000..a5d5f10 --- /dev/null +++ b/2025/schedule/index.html @@ -0,0 +1,147 @@ + + + + + + Schedule - Java Developers' Conference 2025 + + + + + + + + +
+
+
+
+ + + + + + + + +
+
+ + + + + + + + + + + +
TimeSessionSpeaker
+
+
+ + + + + + + + + diff --git a/2025/service-worker.js b/2025/service-worker.js new file mode 100644 index 0000000..f298a26 --- /dev/null +++ b/2025/service-worker.js @@ -0,0 +1,104 @@ +const CACHE_NAME = 'cache-v176139785218'; // ⬅️ bump this on each deploy to bust cache + +// ---- INSTALL ---- +self.addEventListener('install', event => { + console.log('[SW] Installing new version...'); + + event.waitUntil( + fetch('manifest.json', {cache: 'no-store'}) + .then(response => { + if (!response.ok) throw new Error('Failed to fetch manifest.json'); + return response.json(); + }) + .then(data => { + const assetsToCache = (data.assets || []).filter(url => { + const u = url.toLowerCase(); + return !( + u.endsWith('service-worker.js') || + u.endsWith('manifest.json') + ); + }); + + if (!assetsToCache.length) return; // nothing to cache + + // Cache assets individually so one failure doesn't fail the whole install + return caches.open(CACHE_NAME).then(async cache => { + const results = await Promise.all( + assetsToCache.map(async (url) => { + try { + // Fetch with cache: 'reload' to bypass browser HTTP cache + const response = await fetch(url, { cache: 'reload' }); + if (response.ok) { + await cache.put(url, response); + } + return {url, ok: true}; + } catch (e) { + console.warn('[SW] Skipping asset (failed to cache):', url, e); + return {url, ok: false, error: e}; + } + }) + ); + + const failed = results.filter(r => !r.ok); + if (failed.length) { + console.warn(`[SW] Cached ${results.length - failed.length}/${results.length} assets. Some assets failed during install.`); + } else { + console.log(`[SW] Cached ${results.length} assets successfully.`); + } + }); + }) + .catch(err => console.error('[SW] Install error:', err)) + ); + + // Activate immediately — don’t wait for old worker to release control + self.skipWaiting(); +}); + +// ---- ACTIVATE ---- +self.addEventListener('activate', event => { + console.log('[SW] Activating new version...'); + + event.waitUntil( + caches.keys().then(names => + Promise.all( + names.map(name => { + const shouldDelete = name !== CACHE_NAME && (name.startsWith('cache-') || name.startsWith('site-cache-')); + if (shouldDelete) { + console.log('[SW] Deleting old cache:', name); + return caches.delete(name); + } + }) + ) + ).then(() => self.clients.claim()) // Take control of all open pages immediately + ); +}); + +// ---- FETCH ---- +self.addEventListener('fetch', event => { + const reqUrl = new URL(event.request.url); + + // Always bypass cache for these files + if (reqUrl.pathname.endsWith('/service-worker.js') || reqUrl.pathname.endsWith('/manifest.json')) { + event.respondWith(fetch(event.request, {cache: 'no-store'})); + return; + } + + if (!event.request.url.startsWith('http')) { + return; + } + + event.respondWith( + caches.match(event.request).then(cached => { + if (cached) return cached; + + return fetch(event.request).then(response => { + if (!response || response.status !== 200 || response.type !== 'basic') return response; + + const cloned = response.clone(); + caches.open(CACHE_NAME).then(cache => cache.put(event.request, cloned)).catch(() => { + }); + return response; + }); + }).catch(err => console.error('[SW] Fetch failed:', err)) + ); +}); diff --git a/2025/sessions.html b/2025/sessions.html new file mode 100644 index 0000000..2b76dde --- /dev/null +++ b/2025/sessions.html @@ -0,0 +1,75 @@ + + + + + + Sessions - Java Developers' Conference 2025 + + + + + + + + +
+
+
+
+ + + + + + + + +
+ + +
+ +
+ + + +
+ + + + + + + + + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..86db50e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +Do not touch the 2024 folder.