323 lines
10 KiB
PHP
323 lines
10 KiB
PHP
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="ko">
|
||
|
|
<head>
|
||
|
|
<meta charset="UTF-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>김포 날씨 - 실시간 날씨 정보</title>
|
||
|
|
<style>
|
||
|
|
* {
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
box-sizing: border-box;
|
||
|
|
}
|
||
|
|
|
||
|
|
body {
|
||
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
|
|
min-height: 100vh;
|
||
|
|
display: flex;
|
||
|
|
justify-content: center;
|
||
|
|
align-items: center;
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-container {
|
||
|
|
background: rgba(255, 255, 255, 0.1);
|
||
|
|
backdrop-filter: blur(10px);
|
||
|
|
border-radius: 20px;
|
||
|
|
padding: 40px;
|
||
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
|
|
max-width: 500px;
|
||
|
|
width: 100%;
|
||
|
|
text-align: center;
|
||
|
|
position: relative;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-container::before {
|
||
|
|
content: '';
|
||
|
|
position: absolute;
|
||
|
|
top: -50%;
|
||
|
|
left: -50%;
|
||
|
|
width: 200%;
|
||
|
|
height: 200%;
|
||
|
|
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||
|
|
animation: shine 3s infinite;
|
||
|
|
pointer-events: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes shine {
|
||
|
|
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
|
||
|
|
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
|
||
|
|
}
|
||
|
|
|
||
|
|
.location {
|
||
|
|
color: white;
|
||
|
|
font-size: 2.5rem;
|
||
|
|
font-weight: 700;
|
||
|
|
margin-bottom: 10px;
|
||
|
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||
|
|
}
|
||
|
|
|
||
|
|
.date {
|
||
|
|
color: rgba(255, 255, 255, 0.8);
|
||
|
|
font-size: 1.1rem;
|
||
|
|
margin-bottom: 30px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-main {
|
||
|
|
background: rgba(255, 255, 255, 0.15);
|
||
|
|
border-radius: 15px;
|
||
|
|
padding: 30px;
|
||
|
|
margin-bottom: 30px;
|
||
|
|
backdrop-filter: blur(5px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.temperature {
|
||
|
|
font-size: 4rem;
|
||
|
|
font-weight: 300;
|
||
|
|
color: white;
|
||
|
|
margin-bottom: 10px;
|
||
|
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-description {
|
||
|
|
color: white;
|
||
|
|
font-size: 1.5rem;
|
||
|
|
margin-bottom: 20px;
|
||
|
|
text-transform: capitalize;
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-icon {
|
||
|
|
font-size: 3rem;
|
||
|
|
margin-bottom: 20px;
|
||
|
|
animation: float 3s ease-in-out infinite;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes float {
|
||
|
|
0%, 100% { transform: translateY(0px); }
|
||
|
|
50% { transform: translateY(-10px); }
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-details {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(2, 1fr);
|
||
|
|
gap: 20px;
|
||
|
|
margin-top: 30px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.detail-item {
|
||
|
|
background: rgba(255, 255, 255, 0.1);
|
||
|
|
border-radius: 10px;
|
||
|
|
padding: 20px;
|
||
|
|
backdrop-filter: blur(5px);
|
||
|
|
transition: transform 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.detail-item:hover {
|
||
|
|
transform: translateY(-5px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.detail-label {
|
||
|
|
color: rgba(255, 255, 255, 0.8);
|
||
|
|
font-size: 0.9rem;
|
||
|
|
margin-bottom: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.detail-value {
|
||
|
|
color: white;
|
||
|
|
font-size: 1.2rem;
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
.loading {
|
||
|
|
color: white;
|
||
|
|
font-size: 1.2rem;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error {
|
||
|
|
color: #ff6b6b;
|
||
|
|
background: rgba(255, 107, 107, 0.1);
|
||
|
|
border-radius: 10px;
|
||
|
|
padding: 20px;
|
||
|
|
margin-top: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.refresh-btn {
|
||
|
|
background: rgba(255, 255, 255, 0.2);
|
||
|
|
border: none;
|
||
|
|
color: white;
|
||
|
|
padding: 12px 24px;
|
||
|
|
border-radius: 25px;
|
||
|
|
cursor: pointer;
|
||
|
|
font-size: 1rem;
|
||
|
|
margin-top: 20px;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
backdrop-filter: blur(5px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.refresh-btn:hover {
|
||
|
|
background: rgba(255, 255, 255, 0.3);
|
||
|
|
transform: scale(1.05);
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 480px) {
|
||
|
|
.weather-container {
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.location {
|
||
|
|
font-size: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.temperature {
|
||
|
|
font-size: 3rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.weather-details {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<div class="weather-container">
|
||
|
|
<h1 class="location">김포시</h1>
|
||
|
|
<div class="date" id="current-date"></div>
|
||
|
|
|
||
|
|
<div id="weather-content">
|
||
|
|
<div class="loading">날씨 정보를 불러오는 중...</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<button class="refresh-btn" onclick="loadWeather()">새로고침</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
// 김포시 좌표 (위도: 37.6156, 경도: 126.7158)
|
||
|
|
const KIMPO_LAT = 37.6156;
|
||
|
|
const KIMPO_LON = 126.7158;
|
||
|
|
|
||
|
|
// OpenWeatherMap API 키 (무료 계정으로 사용 가능)
|
||
|
|
const API_KEY = 'YOUR_API_KEY'; // 실제 사용시 API 키를 입력하세요
|
||
|
|
|
||
|
|
function getWeatherIcon(weatherCode) {
|
||
|
|
const icons = {
|
||
|
|
'01': '☀️', // 맑음
|
||
|
|
'02': '⛅', // 구름 조금
|
||
|
|
'03': '☁️', // 구름 많음
|
||
|
|
'04': '☁️', // 흐림
|
||
|
|
'09': '🌧️', // 소나기
|
||
|
|
'10': '🌦️', // 비
|
||
|
|
'11': '⛈️', // 천둥번개
|
||
|
|
'13': '❄️', // 눈
|
||
|
|
'50': '🌫️' // 안개
|
||
|
|
};
|
||
|
|
|
||
|
|
const code = weatherCode.toString().substring(0, 2);
|
||
|
|
return icons[code] || '🌤️';
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatDate() {
|
||
|
|
const now = new Date();
|
||
|
|
const options = {
|
||
|
|
year: 'numeric',
|
||
|
|
month: 'long',
|
||
|
|
day: 'numeric',
|
||
|
|
weekday: 'long',
|
||
|
|
hour: '2-digit',
|
||
|
|
minute: '2-digit'
|
||
|
|
};
|
||
|
|
return now.toLocaleDateString('ko-KR', options);
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateDate() {
|
||
|
|
document.getElementById('current-date').textContent = formatDate();
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadWeather() {
|
||
|
|
const weatherContent = document.getElementById('weather-content');
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 실제 API 호출 대신 샘플 데이터 사용 (API 키가 필요하므로)
|
||
|
|
// 실제 사용시 아래 주석을 해제하고 API 키를 입력하세요
|
||
|
|
|
||
|
|
/*
|
||
|
|
const response = await fetch(
|
||
|
|
`https://api.openweathermap.org/data/2.5/weather?lat=${KIMPO_LAT}&lon=${KIMPO_LON}&appid=${API_KEY}&units=metric&lang=kr`
|
||
|
|
);
|
||
|
|
const data = await response.json();
|
||
|
|
*/
|
||
|
|
|
||
|
|
// 샘플 데이터 (실제 API 응답 형태)
|
||
|
|
const data = {
|
||
|
|
main: {
|
||
|
|
temp: 22.5,
|
||
|
|
feels_like: 24.1,
|
||
|
|
humidity: 65,
|
||
|
|
pressure: 1013
|
||
|
|
},
|
||
|
|
weather: [{
|
||
|
|
description: '맑음',
|
||
|
|
icon: '01d'
|
||
|
|
}],
|
||
|
|
wind: {
|
||
|
|
speed: 3.2
|
||
|
|
},
|
||
|
|
visibility: 10000
|
||
|
|
};
|
||
|
|
|
||
|
|
const weather = data.weather[0];
|
||
|
|
const main = data.main;
|
||
|
|
|
||
|
|
weatherContent.innerHTML = `
|
||
|
|
<div class="weather-main">
|
||
|
|
<div class="weather-icon">${getWeatherIcon(weather.icon)}</div>
|
||
|
|
<div class="temperature">${Math.round(main.temp)}°C</div>
|
||
|
|
<div class="weather-description">${weather.description}</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="weather-details">
|
||
|
|
<div class="detail-item">
|
||
|
|
<div class="detail-label">체감 온도</div>
|
||
|
|
<div class="detail-value">${Math.round(main.feels_like)}°C</div>
|
||
|
|
</div>
|
||
|
|
<div class="detail-item">
|
||
|
|
<div class="detail-label">습도</div>
|
||
|
|
<div class="detail-value">${main.humidity}%</div>
|
||
|
|
</div>
|
||
|
|
<div class="detail-item">
|
||
|
|
<div class="detail-label">풍속</div>
|
||
|
|
<div class="detail-value">${data.wind.speed} m/s</div>
|
||
|
|
</div>
|
||
|
|
<div class="detail-item">
|
||
|
|
<div class="detail-label">기압</div>
|
||
|
|
<div class="detail-value">${main.pressure} hPa</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
weatherContent.innerHTML = `
|
||
|
|
<div class="error">
|
||
|
|
날씨 정보를 불러오는데 실패했습니다.<br>
|
||
|
|
잠시 후 다시 시도해주세요.
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
console.error('날씨 데이터 로딩 오류:', error);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 페이지 로드시 날씨 정보 로드
|
||
|
|
document.addEventListener('DOMContentLoaded', function() {
|
||
|
|
updateDate();
|
||
|
|
loadWeather();
|
||
|
|
|
||
|
|
// 매분마다 날짜 업데이트
|
||
|
|
setInterval(updateDate, 60000);
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|