Files
sam-kd/report/git/index.html
hskwon aca1767eb9 초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
2025-12-10 20:14:31 +09:00

474 lines
30 KiB
HTML

<!DOCTYPE html>
<html lang="ko" class="scroll-smooth">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Git & GitHub: 대화형 성장 분석</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">
<!-- Chosen Palette: Calm Harmony (Background: #F8F9FA, Text: #343A40, Accents: #4C6EF5, #228BE6, #15AABF) -->
<!-- Application Structure Plan: A non-linear, thematic SPA with a sticky top navigation (Prologue, Growth, Platform, Culture). The structure is designed as a narrative journey, starting with the origins, moving to quantitative growth, then exploring the current platform, and finishing with culture. This is more engaging than a linear report summary and allows users to jump to sections of interest. Key interactions include a hover-able timeline chart for growth metrics and clickable cards to reveal detailed information about the platform's pillars, encouraging exploration without overwhelming the user. -->
<!-- Visualization & Content Choices:
- Git/GitHub Origins: Goal=Inform. Method=HTML/CSS vertical timeline and info cards. Interaction=Click to reveal text. Justification=Visually separates the two intertwined stories and presents history in a digestible, step-by-step format. Library=None (Vanilla JS/CSS).
- User/Revenue Growth: Goal=Show Change/Compare. Method=Chart.js combined line chart. Interaction=Hover for tooltips with precise data. Justification=Effectively visualizes the explosive growth trends over time in a single, powerful graphic. Library=Chart.js.
- Platform Pillars (Actions, etc.): Goal=Organize/Inform. Method=HTML/CSS interactive cards. Interaction=Click to expand/reveal modal. Justification=Breaks down the complex, integrated platform into its three core components, allowing users to drill down into the specifics of what interests them. Library=None (Vanilla JS/CSS).
- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
<!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
<style>
body {
font-family: 'Noto Sans KR', sans-serif;
background-color: #F8F9FA;
color: #343A40;
}
.chart-container {
position: relative;
width: 100%;
max-width: 900px;
margin-left: auto;
margin-right: auto;
height: 300px;
max-height: 50vh;
}
@media (min-width: 768px) {
.chart-container {
height: 450px;
}
}
.nav-link {
transition: color 0.3s, border-bottom-color 0.3s;
border-bottom: 2px solid transparent;
}
.nav-link:hover, .nav-link.active {
color: #4C6EF5;
border-bottom-color: #4C6EF5;
}
.timeline-item-content {
transition: max-height 0.5s ease-in-out, opacity 0.5s ease-in-out;
max-height: 0;
opacity: 0;
overflow: hidden;
}
.timeline-item.active .timeline-item-content {
max-height: 500px;
opacity: 1;
}
.platform-card {
transition: transform 0.3s, box-shadow 0.3s;
}
.platform-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
</style>
</head>
<body class="antialiased">
<header id="header" class="sticky top-0 z-50 bg-white/80 backdrop-blur-lg shadow-sm">
<nav class="container mx-auto px-4 py-3">
<div class="flex justify-between items-center">
<a href="#hero" class="text-xl font-bold text-gray-800">Git & GitHub Story</a>
<div class="hidden md:flex space-x-6">
<a href="#prologue" class="nav-link font-medium text-gray-600 pb-1">서막</a>
<a href="#growth" class="nav-link font-medium text-gray-600 pb-1">성장</a>
<a href="#platform" class="nav-link font-medium text-gray-600 pb-1">플랫폼</a>
<a href="#culture" class="nav-link font-medium text-gray-600 pb-1">문화</a>
</div>
<button id="mobile-menu-button" class="md:hidden text-gray-700">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path></svg>
</button>
</div>
<div id="mobile-menu" class="hidden md:hidden mt-4 space-y-2">
<a href="#prologue" class="block nav-link font-medium text-gray-600 py-2">서막</a>
<a href="#growth" class="block nav-link font-medium text-gray-600 py-2">성장</a>
<a href="#platform" class="block nav-link font-medium text-gray-600 py-2">플랫폼</a>
<a href="#culture" class="block nav-link font-medium text-gray-600 py-2">문화</a>
</div>
</nav>
</header>
<main>
<section id="hero" class="relative text-center py-24 md:py-32 bg-white">
<div class="container mx-auto px-4">
<h1 class="text-4xl md:text-6xl font-extrabold text-gray-900 mb-4 leading-tight">Git과 GitHub: 세상을 바꾼 코드</h1>
<p class="text-lg md:text-xl text-gray-600 max-w-3xl mx-auto mb-8">분산 버전 관리의 탄생부터 AI 기반 개발 플랫폼으로의 진화까지, 소프트웨어 개발의 역사를 새로 쓴 두 거인의 성장 스토리를 대화형으로 탐험해 보세요.</p>
<a href="#prologue" class="bg-blue-600 text-white font-bold py-3 px-8 rounded-full hover:bg-blue-700 transition-transform duration-300 transform hover:scale-105">탐험 시작하기</a>
</div>
</section>
<section id="prologue" class="py-20 bg-gray-50">
<div class="container mx-auto px-4">
<div class="text-center mb-16">
<h2 class="text-3xl md:text-4xl font-bold text-gray-800">서막: 두 혁신의 탄생</h2>
<p class="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">필요는 발명의 어머니였습니다. 리눅스 커널의 고통이 Git을 낳았고, Git의 잠재력이 GitHub을 탄생시켰습니다.</p>
</div>
<div class="grid md:grid-cols-2 gap-12 items-start">
<div>
<h3 class="text-2xl font-bold text-center mb-8 text-gray-700">Git: 분산 버전 관리의 서막</h3>
<div class="relative pl-8 border-l-2 border-blue-200">
<div class="timeline-item mb-10 cursor-pointer" data-target="git-1">
<div class="absolute w-6 h-6 bg-white border-4 border-blue-500 rounded-full -left-3.5 mt-1.5"></div>
<h4 class="text-lg font-semibold text-blue-600">~2002: 원시적 협업의 시대</h4>
<div id="git-1" class="timeline-item-content">
<p class="mt-2 text-gray-600">리눅스 커널 개발은 패치 파일을 이메일로 주고받는 원시적인 방식으로 이뤄졌습니다. 변경 추적이 어렵고 통합 과정은 '지옥'과 같았습니다.</p>
</div>
</div>
<div class="timeline-item mb-10 cursor-pointer" data-target="git-2">
<div class="absolute w-6 h-6 bg-white border-4 border-blue-500 rounded-full -left-3.5 mt-1.5"></div>
<h4 class="text-lg font-semibold text-blue-600">2002-2005: BitKeeper 논란</h4>
<div id="git-2" class="timeline-item-content">
<p class="mt-2 text-gray-600">상용 DVCS인 BitKeeper를 도입했지만, 오픈소스 정신에 위배된다는 논란과 라이선스 회수 사태로 이어지며 새로운 시스템의 필요성을 촉발시켰습니다.</p>
</div>
</div>
<div class="timeline-item mb-10 cursor-pointer active" data-target="git-3">
<div class="absolute w-6 h-6 bg-white border-4 border-blue-500 rounded-full -left-3.5 mt-1.5"></div>
<h4 class="text-lg font-semibold text-blue-600">2005.04: Git의 탄생</h4>
<div id="git-3" class="timeline-item-content">
<p class="mt-2 text-gray-600">리누스 토르발스가 단 2주 만에 Git 초기 버전을 개발했습니다. '빠른 속도', '완벽한 분산', '강력한 브랜칭'을 핵심 철학으로 삼았습니다.</p>
</div>
</div>
</div>
</div>
<div>
<h3 class="text-2xl font-bold text-center mb-8 text-gray-700">GitHub: 소셜 코딩의 시작</h3>
<div class="space-y-6">
<div class="bg-white p-6 rounded-lg shadow-md border-l-4 border-green-500">
<h4 class="text-xl font-bold text-gray-800">Pull Request</h4>
<p class="mt-2 text-gray-600">코드 변경 제안을 '대화형' 프로세스로 전환하여, 딱딱한 기술 절차를 살아있는 사회적 상호작용으로 만들었습니다.</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-md border-l-4 border-green-500">
<h4 class="text-xl font-bold text-gray-800">프로필과 포크</h4>
<p class="mt-2 text-gray-600">개발자 개개인에게 온라인 정체성을 부여하고, 클릭 한 번으로 다른 프로젝트를 복제하여 기여할 수 있는 문화를 만들었습니다.</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-md border-l-4 border-green-500">
<h4 class="text-xl font-bold text-gray-800">오픈소스 우선 모델</h4>
<p class="mt-2 text-gray-600">공개 저장소는 무료, 비공개 저장소는 유료로 제공하여 커뮤니티의 지지를 얻고 안정적인 비즈니스 기반을 마련했습니다.</p>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="growth" class="py-20 bg-white">
<div class="container mx-auto px-4">
<div class="text-center mb-16">
<h2 class="text-3xl md:text-4xl font-bold text-gray-800">성장: 숫자와 사건들</h2>
<p class="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">부트스트랩 스타트업에서 시작하여 Microsoft에 75억 달러에 인수되기까지, GitHub의 경이로운 성장 과정을 숫자로 확인해 보세요.</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 text-center mb-16">
<div class="bg-gray-50 p-6 rounded-lg shadow">
<p class="text-5xl font-extrabold text-blue-600">1억+</p>
<p class="text-lg font-medium text-gray-700 mt-2">개발자 사용자 (2023)</p>
</div>
<div class="bg-gray-50 p-6 rounded-lg shadow">
<p class="text-5xl font-extrabold text-green-600">$20억</p>
<p class="text-lg font-medium text-gray-700 mt-2">연간 반복 매출 (2024)</p>
</div>
<div class="bg-gray-50 p-6 rounded-lg shadow">
<p class="text-5xl font-extrabold text-indigo-600">$75억</p>
<p class="text-lg font-medium text-gray-700 mt-2">Microsoft 인수 금액 (2018)</p>
</div>
</div>
<div class="bg-gray-50 p-4 sm:p-8 rounded-lg shadow-lg">
<h3 class="text-2xl font-bold text-center mb-6 text-gray-800">사용자 및 매출 성장 추이</h3>
<div class="chart-container">
<canvas id="growthChart"></canvas>
</div>
</div>
</div>
</section>
<section id="platform" class="py-20 bg-gray-50">
<div class="container mx-auto px-4">
<div class="text-center mb-16">
<h2 class="text-3xl md:text-4xl font-bold text-gray-800">플랫폼: 통합된 개발자 경험</h2>
<p class="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">단순 코드 저장소를 넘어, 아이디어 구상부터 배포까지 전 과정을 책임지는 통합 개발 플랫폼으로 진화했습니다. 이 '철의 삼각지대'를 만나보세요.</p>
</div>
<div class="grid md:grid-cols-3 gap-8">
<div class="platform-card bg-white p-8 rounded-lg shadow-lg text-center cursor-pointer" data-modal="actions-modal">
<div class="text-5xl mb-4 text-indigo-500">⚙️</div>
<h3 class="text-2xl font-bold mb-2">GitHub Actions</h3>
<p class="text-gray-600">빌드, 테스트, 배포 파이프라인을 코드와 함께 관리하는 CI/CD 자동화 플랫폼입니다.</p>
</div>
<div class="platform-card bg-white p-8 rounded-lg shadow-lg text-center cursor-pointer" data-modal="codespaces-modal">
<div class="text-5xl mb-4 text-green-500">💻</div>
<h3 class="text-2xl font-bold mb-2">GitHub Codespaces</h3>
<p class="text-gray-600">클릭 한 번으로 즉시 사용 가능한, 완벽하게 구성된 클라우드 개발 환경입니다.</p>
</div>
<div class="platform-card bg-white p-8 rounded-lg shadow-lg text-center cursor-pointer" data-modal="copilot-modal">
<div class="text-5xl mb-4 text-red-500">🤖</div>
<h3 class="text-2xl font-bold mb-2">GitHub Copilot</h3>
<p class="text-gray-600">코딩 방식을 바꾸는 AI 페어 프로그래머. 코드 제안부터 함수 생성까지 지원합니다.</p>
</div>
</div>
</div>
</section>
<section id="culture" class="py-20 bg-white">
<div class="container mx-auto px-4">
<div class="text-center mb-16">
<h2 class="text-3xl md:text-4xl font-bold text-gray-800">문화: 원격 근무와 개발자 중심주의</h2>
<p class="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">GitHub의 성공은 기술뿐 아니라 독특한 기업 문화에 있습니다. 개발자를 최우선으로 생각하고 원격 근무를 선도한 그들의 이야기를 들어보세요.</p>
</div>
<div class="grid md:grid-cols-2 gap-12 items-center">
<div class="bg-gray-50 p-8 rounded-lg shadow-lg">
<h3 class="text-2xl font-bold mb-4 text-gray-800">개발자 우선(Developer-First) 철학</h3>
<p class="text-gray-600 mb-4">관리자는 지시자가 아닌 '조력자'입니다. 팀원들이 겪는 장애물을 제거하고 그들의 성장을 돕는 것이 핵심 역할입니다.</p>
<ul class="space-y-2 text-gray-700">
<li class="flex items-start"><span class="text-blue-500 mr-2"></span><span>직원의 자율성과 역량 극대화 추구</span></li>
<li class="flex items-start"><span class="text-blue-500 mr-2"></span><span>오픈소스 기반의 공유와 협업 가치 내재화</span></li>
<li class="flex items-start"><span class="text-blue-500 mr-2"></span><span>개발자의 만족도가 곧 제품의 혁신으로 연결</span></li>
</ul>
</div>
<div class="bg-gray-50 p-8 rounded-lg shadow-lg">
<h3 class="text-2xl font-bold mb-4 text-gray-800">원격 근무의 선구자</h3>
<p class="text-gray-600 mb-4">팬데믹 이전부터 '원격 근무 우선' 문화를 구축했습니다. 2023년에는 모든 사무실을 폐쇄하고 '완전 원격 근무' 체제로 전환하며, 위기를 문화적 강점을 활용한 전략적 기회로 바꾸었습니다.</p>
<ul class="space-y-2 text-gray-700">
<li class="flex items-start"><span class="text-green-500 mr-2"></span><span>전 세계 우수 인재 유치에 유리</span></li>
<li class="flex items-start"><span class="text-green-500 mr-2"></span><span>부동산 등 고정 비용 절감 효과</span></li>
<li class="flex items-start"><span class="text-green-500 mr-2"></span><span>높은 자율성에 기반한 신뢰 문화 구축</span></li>
</ul>
</div>
</div>
</div>
</section>
</main>
<footer class="bg-gray-800 text-white py-8">
<div class="container mx-auto px-4 text-center">
<p>Git과 GitHub의 이야기는 계속됩니다.</p>
<p class="text-sm text-gray-400 mt-2">AI 시대의 개발 플랫폼 리더로서 그들의 미래를 주목해 주세요.</p>
</div>
</footer>
<!-- Modals -->
<div id="modal-container" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden items-center justify-center p-4">
<div id="actions-modal" class="modal-content hidden bg-white rounded-lg shadow-xl p-8 max-w-2xl w-full">
<h2 class="text-2xl font-bold mb-4">GitHub Actions ⚙️</h2>
<p class="mb-4">GitHub Actions는 CI/CD(지속적 통합/지속적 배포)를 자동화하는 플랫폼입니다. 코드 저장소에서 직접 빌드, 테스트, 배포 파이프라인을 설정하고 실행할 수 있어 개발 워크플로를 혁신합니다.</p>
<ul class="list-disc list-inside space-y-2">
<li><span class="font-semibold">Workflows:</span> YAML 파일로 자동화 프로세스를 정의합니다.</li>
<li><span class="font-semibold">Events:</span> `push`, `pull_request` 등 워크플로를 시작시키는 트리거입니다.</li>
<li><span class="font-semibold">Runners:</span> 작업을 실행하는 가상 머신(Linux, Windows, macOS)입니다.</li>
<li><span class="font-semibold">Marketplace:</span> 커뮤니티가 만든 재사용 가능한 액션 라이브러리입니다.</li>
</ul>
<button class="modal-close mt-6 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300">닫기</button>
</div>
<div id="codespaces-modal" class="modal-content hidden bg-white rounded-lg shadow-xl p-8 max-w-2xl w-full">
<h2 class="text-2xl font-bold mb-4">GitHub Codespaces 💻</h2>
<p class="mb-4">GitHub Codespaces는 컨테이너 기술을 기반으로 하는 즉각적인 클라우드 개발 환경입니다. 로컬 머신에 복잡한 설정을 할 필요 없이, 브라우저에서 바로 코딩을 시작할 수 있습니다.</p>
<ul class="list-disc list-inside space-y-2">
<li><span class="font-semibold">환경 일관성:</span> 모든 팀원이 동일한 개발 환경을 사용해 "내 컴퓨터에서는 되는데" 문제를 해결합니다.</li>
<li><span class="font-semibold">기여 장벽 완화:</span> 신규 참여자가 환경 설정 없이 즉시 프로젝트에 기여할 수 있습니다.</li>
<li><span class="font-semibold">어디서든 개발:</span> 인터넷만 연결되어 있다면 어떤 기기에서든 개발이 가능합니다.</li>
</ul>
<button class="modal-close mt-6 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300">닫기</button>
</div>
<div id="copilot-modal" class="modal-content hidden bg-white rounded-lg shadow-xl p-8 max-w-2xl w-full">
<h2 class="text-2xl font-bold mb-4">GitHub Copilot 🤖</h2>
<p class="mb-4">GitHub Copilot은 OpenAI와 공동 개발한 AI 페어 프로그래머입니다. 개발자의 코딩 스타일과 문맥을 이해하여 실시간으로 코드를 제안하고 생산성을 극대화합니다.</p>
<ul class="list-disc list-inside space-y-2">
<li><span class="font-semibold">코드 자동 완성:</span> 단일 라인부터 함수 전체까지 지능적으로 코드를 제안합니다.</li>
<li><span class="font-semibold">자연어-코드 변환:</span> 주석으로 원하는 기능을 설명하면 코드로 변환해 줍니다.</li>
<li><span class="font-semibold">반복 작업 가속화:</span> 상용구(boilerplate) 코드를 신속하게 작성하여 시간을 절약합니다.</li>
</ul>
<button class="modal-close mt-6 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300">닫기</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const growthData = {
labels: ['2012', '2015', '2016', '2018', '2022', '2023', '2024'],
users: [null, null, null, 28, 90, 100, null],
revenue: [null, null, 1.4, 2, 10, null, 20],
events: [
{ year: '2012', label: 'Series A: $1억' },
{ year: '2015', label: 'Series B: $2.5억' },
{ year: '2018', label: 'Microsoft 인수: $75억' },
{ year: '2022', label: 'ARR $10억 달성' },
{ year: '2023', label: '사용자 1억명 돌파' },
{ year: '2024', label: 'ARR $20억 달성' },
]
};
const ctx = document.getElementById('growthChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: growthData.labels,
datasets: [
{
label: '개발자 사용자 (백만 명)',
data: growthData.users,
borderColor: '#4C6EF5',
backgroundColor: 'rgba(76, 110, 245, 0.1)',
yAxisID: 'yUsers',
tension: 0.3,
fill: true,
},
{
label: '연간 반복 매출 (억 달러)',
data: growthData.revenue,
borderColor: '#228BE6',
backgroundColor: 'rgba(34, 139, 230, 0.1)',
yAxisID: 'yRevenue',
tension: 0.3,
fill: true,
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false,
},
scales: {
yUsers: {
type: 'linear',
display: true,
position: 'left',
title: {
display: true,
text: '사용자 (백만 명)',
color: '#4C6EF5'
}
},
yRevenue: {
type: 'linear',
display: true,
position: 'right',
title: {
display: true,
text: '매출 (억 달러)',
color: '#228BE6'
},
grid: {
drawOnChartArea: false,
},
}
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += context.parsed.y;
if (context.dataset.yAxisID === 'yUsers') {
label += '백만 명';
} else {
label += '억 달러';
}
}
return label;
}
}
},
annotation: {
annotations: growthData.events.map(event => ({
type: 'point',
xValue: event.year,
yValue: growthData.users[growthData.labels.indexOf(event.year)] ?? growthData.revenue[growthData.labels.indexOf(event.year)],
backgroundColor: 'rgba(255, 99, 132, 0.5)',
radius: 5,
pointStyle: 'rectRot',
callout: {
enabled: true,
content: event.label,
position: 'auto',
},
}))
}
}
}
});
// Mobile menu toggle
const mobileMenuButton = document.getElementById('mobile-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
});
// Close mobile menu on link click
document.querySelectorAll('#mobile-menu a').forEach(link => {
link.addEventListener('click', () => {
mobileMenu.classList.add('hidden');
});
});
// Active nav link on scroll
const sections = document.querySelectorAll('section');
const navLinks = document.querySelectorAll('.nav-link');
window.addEventListener('scroll', () => {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
if (pageYOffset >= sectionTop - 80) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href').includes(current)) {
link.classList.add('active');
}
});
});
// Timeline interaction
const timelineItems = document.querySelectorAll('.timeline-item');
timelineItems.forEach(item => {
item.addEventListener('click', () => {
timelineItems.forEach(i => i.classList.remove('active'));
item.classList.add('active');
});
});
// Modal interaction
const modalContainer = document.getElementById('modal-container');
const platformCards = document.querySelectorAll('.platform-card');
const closeButtons = document.querySelectorAll('.modal-close');
platformCards.forEach(card => {
card.addEventListener('click', () => {
const modalId = card.dataset.modal;
const modal = document.getElementById(modalId);
modalContainer.style.display = 'flex';
modal.classList.remove('hidden');
});
});
const closeModal = () => {
modalContainer.style.display = 'none';
document.querySelectorAll('.modal-content').forEach(modal => {
modal.classList.add('hidden');
});
};
closeButtons.forEach(button => {
button.addEventListener('click', closeModal);
});
modalContainer.addEventListener('click', (e) => {
if(e.target === modalContainer) {
closeModal();
}
});
});
</script>
</body>
</html>