Browse Source

dashboard node

master
skrabanek 3 weeks ago
parent
commit
c934f5d496
  1. 26
      makerfest_dashboard/index.html
  2. 1238
      makerfest_dashboard/package-lock.json
  3. 18
      makerfest_dashboard/package.json
  4. 77
      makerfest_dashboard/src/App.vue
  5. 4
      makerfest_dashboard/src/main.js
  6. 8
      makerfest_dashboard/vite.config.js

26
makerfest_dashboard/index.html

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="cs" data-bs-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MakerFest Dashboard - SŠ Štětí</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background-color: #121212; color: #e0e0e0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.weather-card {
background: linear-gradient(145deg, #1e1e1e, #252525);
border: 1px solid #333;
border-radius: 15px;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
}
.weather-card:hover { transform: translateY(-5px); border-color: #0d6efd; box-shadow: 0 8px 25px rgba(13, 110, 253, 0.3); }
.temp-display { font-size: 3.5rem; font-weight: bold; }
.glow-blue { box-shadow: 0 0 15px rgba(0, 123, 255, 0.2); }
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

1238
makerfest_dashboard/package-lock.json

File diff suppressed because it is too large

18
makerfest_dashboard/package.json

@ -0,0 +1,18 @@
{
"name": "makerfest-dashboard",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.4.0",
"bootstrap": "^5.3.3"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.0",
"vite": "^5.0.0"
}
}

77
makerfest_dashboard/src/App.vue

@ -0,0 +1,77 @@
<template>
<div class="container-fluid py-4 min-vh-100 d-flex flex-column">
<header class="text-center mb-5">
<h1 class="display-4 fw-bold text-primary">MakerFest 2026</h1>
<p class="lead"> Štětí & PaperBox Robotic Team</p>
<div class="badge bg-secondary">Aktualizace každých 5 minut | Poslední: {{ lastUpdate }}</div>
</header>
<main class="row g-4 flex-grow-1">
<div v-for="city in cities" :key="city.id" class="col-md-4">
<div class="weather-card h-100 p-4 d-flex flex-column align-items-center text-center">
<h2 class="h1 mb-3">{{ city.name }}</h2>
<div v-if="city.data">
<img :src="'https://openweathermap.org/img/wn/' + city.data.weather[0].icon + '@4x.png'" :alt="city.data.weather[0].description">
<div class="temp-display">{{ Math.round(city.data.main.temp) }}°C</div>
<p class="h4 text-capitalize">{{ city.data.weather[0].description }}</p>
<div class="mt-4 w-100 border-top pt-3 row">
<div class="col-6">
<small class="text-muted d-block">Vlhkost</small>
<strong>{{ city.data.main.humidity }}%</strong>
</div>
<div class="col-6">
<small class="text-muted d-block">Vítr</small>
<strong>{{ city.data.wind.speed }} m/s</strong>
</div>
</div>
<p class="mt-3 mb-0 small text-muted">Pocitově: {{ Math.round(city.data.main.feels_like) }}°C</p>
</div>
<div v-else class="spinner-border text-primary my-auto" role="status">
<span class="visually-hidden">Načítání...</span>
</div>
</div>
</div>
</main>
<footer class="text-center mt-5 text-muted">
<small>&copy; 2026 Štětí - Robotický tým PaperBox</small>
</footer>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const API_KEY = 'f70d944f638a7ae77de89435d4d23c01'
const lastUpdate = ref(new Date().toLocaleTimeString())
const cities = ref([
{ id: 'steti', name: 'Štětí', query: 'Steti,CZ', data: null },
{ id: 'usti', name: 'Ústí nad Labem', query: 'Usti nad Labem,CZ', data: null },
{ id: 'praha', name: 'Praha', query: 'Prague,CZ', data: null }
])
async function fetchWeather() {
for (const city of cities.value) {
try {
const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city.query}&units=metric&lang=cz&appid=${API_KEY}`)
if (!response.ok) throw new Error(`Chyba pro ${city.name}`)
city.data = await response.json()
} catch (err) {
console.error(err)
}
}
lastUpdate.value = new Date().toLocaleTimeString()
}
let interval = null
onMounted(() => {
fetchWeather()
interval = setInterval(fetchWeather, 300000) // 5 minut
})
onUnmounted(() => {
if (interval) clearInterval(interval)
})
</script>

4
makerfest_dashboard/src/main.js

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

8
makerfest_dashboard/vite.config.js

@ -0,0 +1,8 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
root: './',
base: './'
})
Loading…
Cancel
Save