mirror of
https://github.com/headporter81/specialsource-homepage-frontend.git
synced 2026-10-07 15:21:10 +09:00
This commit is contained in:
@@ -209,6 +209,13 @@ body, html { margin: 0; padding: 0; width: 100%; height: 100%; background-color:
|
||||
font-size: 11px; font-weight: bold; padding: 3px 8px; border: 1px solid currentColor;
|
||||
background: rgba(0, 0, 0, 0.5); letter-spacing: 1px; border-radius: 2px; display: inline-block;
|
||||
}
|
||||
.weather-panel { text-align: center; }
|
||||
.weather-ascii {
|
||||
font-family: inherit; white-space: pre; text-align: left; display: inline-block;
|
||||
font-size: 11px; line-height: 1.15; color: var(--tui-color); text-shadow: 0 0 4px var(--tui-glow);
|
||||
margin: 0 0 8px; border: none; background: transparent;
|
||||
}
|
||||
.weather-loading { font-size: 11px; color: var(--tui-dim); letter-spacing: 0.05em; padding: 8px 0; }
|
||||
|
||||
/* 📺 유튜브 그리드 레이아웃 */
|
||||
#videos-container {
|
||||
|
||||
@@ -75,6 +75,17 @@
|
||||
<span :class="['dash-chip', currentServerSource]">[{{ currentServerSourceDisplay }}]</span>
|
||||
</div>
|
||||
|
||||
<div class="dash-panel weather-panel">
|
||||
<h4>SEOUL WEATHER</h4>
|
||||
<div v-if="weather.loading" class="weather-loading">SYNCING...</div>
|
||||
<div v-else-if="weather.error" class="weather-loading">SYNC FAILED</div>
|
||||
<template v-else>
|
||||
<pre class="weather-ascii">{{ weatherIcon }}</pre>
|
||||
<div class="dash-stat"><span>TEMP</span><b>{{ weather.temp }}°C</b></div>
|
||||
<div class="dash-stat"><span>COND</span><b>{{ weatherLabel }}</b></div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="dash-panel">
|
||||
<h4>SESSION</h4>
|
||||
<div class="dash-stat"><span>USER</span><b>{{ isLoggedIn ? currentUsername : 'anonymous' }}</b></div>
|
||||
@@ -271,9 +282,77 @@ const showSystemAlert = (message) => {
|
||||
const todayUnique = ref(0);
|
||||
const activeNow = ref(0);
|
||||
let analyticsTimer = null;
|
||||
let weatherTimer = null;
|
||||
|
||||
const currentServerSource = ref('nas');
|
||||
|
||||
const WEATHER_ICONS = {
|
||||
clear: " \\ /\n .-.\n ― ( ) ―\n `-'\n / \\",
|
||||
cloudy: " .--.\n .-( ).\n (___.__)__)",
|
||||
overcast: " .--.\n .-( ).\n (___.__)__)",
|
||||
fog: " _ - _ - _\n_ - _ - _ -\n _ - _ - _",
|
||||
drizzle: " .-.\n ( ).\n (___(__)\n ' ' ' '",
|
||||
rain: " .-.\n ( ).\n (___(__)\n ' ' ' ' '",
|
||||
snow: " .-.\n ( ).\n (___(__)\n * * *",
|
||||
thunder: " .-.\n ( ).\n (___(__)\n ⚡ ' ⚡"
|
||||
};
|
||||
|
||||
const WEATHER_LABELS = {
|
||||
clear: '맑음',
|
||||
cloudy: '구름 조금',
|
||||
overcast: '흐림',
|
||||
fog: '안개',
|
||||
drizzle: '이슬비',
|
||||
rain: '비',
|
||||
snow: '눈',
|
||||
thunder: '뇌우'
|
||||
};
|
||||
|
||||
const getWeatherIconKey = (code) => {
|
||||
if (code === 0) return 'clear';
|
||||
if (code === 1 || code === 2) return 'cloudy';
|
||||
if (code === 3) return 'overcast';
|
||||
if (code === 45 || code === 48) return 'fog';
|
||||
if ([51, 53, 55, 56, 57].includes(code)) return 'drizzle';
|
||||
if ([61, 63, 65, 66, 67, 80, 81, 82].includes(code)) return 'rain';
|
||||
if ([71, 73, 75, 77, 85, 86].includes(code)) return 'snow';
|
||||
if ([95, 96, 99].includes(code)) return 'thunder';
|
||||
return 'cloudy';
|
||||
};
|
||||
|
||||
const weather = ref({ loading: true, error: false, temp: null, iconKey: 'clear' });
|
||||
const weatherIcon = computed(() => WEATHER_ICONS[weather.value.iconKey] || WEATHER_ICONS.cloudy);
|
||||
const weatherLabel = computed(() => WEATHER_LABELS[weather.value.iconKey] || '');
|
||||
|
||||
const fetchWeatherData = async () => {
|
||||
try {
|
||||
const res = await axios.get('https://api.open-meteo.com/v1/forecast', {
|
||||
params: {
|
||||
latitude: 37.5665,
|
||||
longitude: 126.9780,
|
||||
current_weather: true,
|
||||
timezone: 'Asia/Seoul'
|
||||
}
|
||||
});
|
||||
const current = res.data && res.data.current_weather;
|
||||
if (current) {
|
||||
weather.value = {
|
||||
loading: false,
|
||||
error: false,
|
||||
temp: Math.round(current.temperature),
|
||||
iconKey: getWeatherIconKey(current.weathercode)
|
||||
};
|
||||
} else {
|
||||
weather.value.loading = false;
|
||||
weather.value.error = true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("날씨 데이터 로드 실패:", err);
|
||||
weather.value.loading = false;
|
||||
weather.value.error = true;
|
||||
}
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{ id: 'main', name: 'HOME' },
|
||||
{ id: 'youtube', name: 'YOUTUBE' },
|
||||
@@ -499,6 +578,7 @@ onMounted(() => {
|
||||
|
||||
fetchVideos();
|
||||
fetchAnalyticsData();
|
||||
fetchWeatherData();
|
||||
|
||||
detectRealtimeServerSource();
|
||||
|
||||
@@ -507,6 +587,8 @@ onMounted(() => {
|
||||
detectRealtimeServerSource();
|
||||
}, 30000);
|
||||
|
||||
weatherTimer = setInterval(fetchWeatherData, 600000);
|
||||
|
||||
const globaljQuery = window.$;
|
||||
if (globaljQuery && terminalRef.value) {
|
||||
termInstance.value = globaljQuery(terminalRef.value).terminal({
|
||||
@@ -595,5 +677,6 @@ onMounted(() => {
|
||||
|
||||
onUnmounted(() => {
|
||||
if (analyticsTimer) clearInterval(analyticsTimer);
|
||||
if (weatherTimer) clearInterval(weatherTimer);
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user