Τελικός κώδικας για το πρόγραμμα καιρού

Αντιγράψτε και αποθηκεύστε τον παρακάτω κώδικα στα αντίστοιχα αρχεία (index.html, style.css, script.js).


1. Αρχείο: index.html

(Η βασική δομή της εφαρμογής. Περιέχει τη φόρμα εισαγωγής και το "κοντέινερ" όπου θα εμφανιστούν οι πληροφορίες του καιρού.)

<!DOCTYPE html>
<html lang="el">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Εφαρμογή Καιρού</title>
    <link rel="stylesheet" href="style.css">
    <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=Roboto:wght@400;700&display=swap" rel="stylesheet">
</head>
<body>
    <div class="app-container">
        <header>
            <h1>Εφαρμογή Καιρού</h1>
        </header>
        
        <main>
            <form id="city-form">
                <input type="text" id="city-input" placeholder="π.χ. Αθήνα, Θεσσαλονίκη..." required>
                <button type="submit">Αναζήτηση</button>
            </form>

            <div id="weather-display" class="hidden">
                <h2 id="city-name"></h2>
                <div class="weather-main">
                    <img id="weather-icon" src="" alt="Εικονίδιο καιρού">
                    <p id="temperature"></p>
                </div>
                <p id="weather-description"></p>
            </div>

            <div id="loading-spinner" class="hidden"></div>
        </main>
    </div>
    
    <script src="script.js"></script>
</body>
</html>

2. Αρχείο: style.css

(Το styling που κάνει την εφαρμογή να φαίνεται καθαρή, μοντέρνα και responsive. Περιλαμβάνει και ένα απλό spinner για την ώρα της φόρτωσης.)

/* --- Basic Resets & Body Styles --- */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Roboto', sans-serif;
    background: linear-gradient(135deg, #71b7e6, #9b59b6);
    color: #333;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

/* --- App Container --- */
.app-container {
    background: rgba(255, 255, 255, 0.9);
    padding: 2rem;
    border-radius: 15px;
    box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.18);
    width: 90%;
    max-width: 450px;
    text-align: center;
}

header h1 {
    margin-bottom: 1.5rem;
    color: #333;
    font-weight: 700;
}

/* --- Form Styles --- */
#city-form {
    display: flex;
    margin-bottom: 2rem;
}

#city-input {
    flex-grow: 1;
    padding: 0.8rem;
    border: 1px solid #ccc;
    border-radius: 8px 0 0 8px;
    font-size: 1rem;
    outline: none;
}
#city-input:focus {
    border-color: #007bff;
}

#city-form button {
    padding: 0.8rem 1rem;
    border: none;
    background: #007bff;
    color: white;
    font-size: 1rem;
    cursor: pointer;
    border-radius: 0 8px 8px 0;
    transition: background-color 0.3s;
}

#city-form button:hover {
    background: #0056b3;
}

/* --- Weather Display --- */
#weather-display {
    animation: fadeIn 0.5s ease-in-out;
}

#city-name {
    margin-bottom: 1rem;
    font-size: 2rem;
}

.weather-main {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-bottom: 1rem;
}

#temperature {
    font-size: 3.5rem;
    font-weight: 700;
    margin-left: 1rem;
}

#weather-icon {
    width: 100px;
    height: 100px;
}

#weather-description {
    font-size: 1.2rem;
    text-transform: capitalize;
}

/* --- Utility & Animation --- */
.hidden {
    display: none;
}

#loading-spinner {
    border: 5px solid #f3f3f3;
    border-top: 5px solid #007bff;
    border-radius: 50%;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
    margin: 20px auto;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

@keyframes fadeIn {
    from { opacity: 0; transform: scale(0.9); }
    to { opacity: 1; transform: scale(1); }
}


3. Αρχείο: script.js

(Η καρδιά της εφαρμογής. Περιλαμβάνει την επικοινωνία με το API, τον χειρισμό των δεδομένων και την ενημέρωση της σελίδας.)

// ΣΗΜΑΝΤΙΚΟ: Αντικαταστήστε αυτό με το δικό σας, προσωπικό API Key από το openweathermap.org
const apiKey = 'YOUR_SECRET_API_KEY'; 

// --- Επιλογή Στοιχείων του DOM ---
const cityForm = document.getElementById('city-form');
const cityInput = document.getElementById('city-input');
const weatherDisplay = document.getElementById('weather-display');
const loadingSpinner = document.getElementById('loading-spinner');

// --- Προσθήκη Event Listener στη Φόρμα ---
cityForm.addEventListener('submit', async (event) => {
    // 1. Αποτρέπουμε την προκαθορισμένη συμπεριφορά της φόρμας (ανανέωση σελίδας)
    event.preventDefault();

    // 2. Παίρνουμε την πόλη που έγραψε ο χρήστης και αφαιρούμε τυχόν κενά
    const city = cityInput.value.trim();

    // Αν δεν έχει γράψει τίποτα, δεν κάνουμε κάτι
    if (!city) {
        alert('Παρακαλώ εισάγετε μια πόλη.');
        return;
    }

    // Εμφανίζουμε το spinner και κρύβουμε τις παλιές πληροφορίες
    loadingSpinner.classList.remove('hidden');
    weatherDisplay.classList.add('hidden');
    
    // 3. Καλούμε τη συνάρτηση για να φέρει τα δεδομένα του καιρού
    getWeatherData(city);
});

// --- Συνάρτηση για την κλήση του API ---
async function getWeatherData(city) {
    // Κατασκευάζουμε το URL του API με τις απαραίτητες παραμέτρους
    const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric&lang=el`;

    try {
        const response = await fetch(apiUrl);
        
        // Αν η απάντηση δεν είναι ΟΚ (π.χ. 404 Not Found), δημιουργούμε ένα σφάλμα
        if (!response.ok) {
            throw new Error(`Η πόλη "${city}" δεν βρέθηκε. Δοκιμάστε ξανά.`);
        }
        
        const data = await response.json();
        
        // Αν όλα πήγαν καλά, καλούμε τη συνάρτηση για την εμφάνιση των δεδομένων
        displayWeatherData(data);

    } catch (error) {
        // Αν υπάρξει οποιοδήποτε σφάλμα, το εμφανίζουμε στον χρήστη
        alert(error.message);
        console.error("Fetch Error:", error);
    } finally {
        // Κρύβουμε το spinner σε κάθε περίπτωση (είτε επιτυχία είτε αποτυχία)
        loadingSpinner.classList.add('hidden');
    }
}


// --- Συνάρτηση για την Εμφάνιση των Δεδομένων στο DOM ---
function displayWeatherData(data) {
    // Παίρνουμε τις πληροφορίες που χρειαζόμαστε από το αντικείμενο 'data'
    const cityName = data.name;
    const temperature = data.main.temp;
    const description = data.weather[0].description;
    const iconCode = data.weather[0].icon;
    const iconUrl = `https://openweathermap.org/img/wn/${iconCode}@2x.png`;

    // Ενημερώνουμε τα στοιχεία της σελίδας με τις νέες πληροφορίες
    document.getElementById('city-name').textContent = cityName;
    document.getElementById('temperature').textContent = `${Math.round(temperature)}°C`;
    document.getElementById('weather-description').textContent = description;
    document.getElementById('weather-icon').src = iconUrl;
    document.getElementById('weather-icon').alt = `Εικονίδιο για ${description}`;

    // Εμφανίζουμε το κοντέινερ των πληροφοριών
    weatherDisplay.classList.remove('hidden');
}