Weather Dashboard Source Code

Complete source code for the Weather Dashboard built with Nahir UI and K2

About This Example

This Weather Dashboard demonstrates how to build a data-driven application using Nahir UI, K2's component-based UI framework. The application includes:

  • API integration with a weather service
  • Data caching using K2's ramdisk cache
  • Dynamic UI rendering based on data
  • Search functionality
  • Loading and error states
  • Responsive layout

The application uses Nahir UI's ramdisk caching to store weather data, reducing API calls and providing ultra-fast rendering even with large datasets.

weather_app.k2
# Weather Dashboard Example using Nahir UI
import NahirUI
import HTTP

# API configuration
const API_KEY = "your_api_key_here"
const API_BASE_URL = "https://api.weatherapi.com/v1"

# Weather Dashboard component
component WeatherDashboard {
  state = {
    city: "New York",
    currentWeather: null,
    forecast: [],
    loading: false,
    error: null
  }
  
  # Initialize component
  function init() {
    fetchWeatherData(state.city)
  }
  
  # Fetch weather data from API
  function fetchWeatherData(city) {
    state.loading = true
    state.error = null
    updateState()
    
    # Check if data is in cache
    const cacheKey = "weather_" + city.toLowerCase()
    const cachedData = Cache.get(cacheKey)
    
    if (cachedData && Date.now() - cachedData.timestamp < 3600000) {
      # Use cached data if less than 1 hour old
      state.currentWeather = cachedData.currentWeather
      state.forecast = cachedData.forecast
      state.loading = false
      updateState()
      return
    }
    
    # Fetch from API if not in cache or cache is stale
    const url = `${API_BASE_URL}/forecast.json?key=${API_KEY}&q=${city}&days=5`
    
    HTTP.get(url)
      .then(function(response) {
        if (response.status == 200) {
          const data = response.json()
          
          # Parse current weather
          state.currentWeather = {
            temperature: data.current.temp_f,
            condition: data.current.condition.text,
            icon: getWeatherIcon(data.current.condition.code),
            humidity: data.current.humidity,
            wind: data.current.wind_mph,
            pressure: data.current.pressure_mb,
            uv: data.current.uv,
            location: data.location.name + ", " + data.location.country
          }
          
          # Parse forecast
          state.forecast = data.forecast.forecastday.map(function(day) {
            return {
              date: new Date(day.date).toLocaleDateString("en-US", { weekday: "short" }),
              icon: getWeatherIcon(day.day.condition.code),
              highTemp: day.day.maxtemp_f,
              lowTemp: day.day.mintemp_f
            }
          })
          
          # Cache the data
          Cache.set(cacheKey, {
            currentWeather: state.currentWeather,
            forecast: state.forecast,
            timestamp: Date.now()
          })
          
          state.loading = false
          updateState()
        } else {
          state.error = "Error fetching weather data"
          state.loading = false
          updateState()
        }
      })
      .catch(function(error) {
        state.error = error.message
        state.loading = false
        updateState()
      })
  }
  
  # Map weather condition code to icon
  function getWeatherIcon(code) {
    if (code == 1000) return "fa-sun"
    if (code >= 1003 && code <= 1009) return "fa-cloud-sun"
    if (code >= 1030 && code <= 1039) return "fa-smog"
    if (code >= 1063 && code <= 1069) return "fa-cloud-rain"
    if (code >= 1114 && code <= 1117) return "fa-snowflake"
    if (code >= 1135 && code <= 1147) return "fa-fog"
    if (code >= 1150 && code <= 1201) return "fa-cloud-showers-heavy"
    if (code >= 1204 && code <= 1237) return "fa-snowflake"
    if (code >= 1240 && code <= 1246) return "fa-cloud-rain"
    if (code >= 1249 && code <= 1264) return "fa-snowflake"
    if (code >= 1273 && code <= 1282) return "fa-bolt"
    return "fa-cloud"
  }
  
  # Handle search
  function handleSearch() {
    fetchWeatherData(state.city)
  }
  
  # Handle input change
  function handleInputChange(e) {
    state.city = e.target.value
    updateState()
  }
  
  # Update component state
  function updateState() {
    this.setState(state)
  }
  
  render {
    element = "div"
    className = "weather-app"
    children = [
      # Header
      {
        element: "div",
        className: "weather-header",
        children: [
          {
            element: "h2",
            content: "Weather Dashboard"
          },
          {
            element: "span",
            content: "Powered by Nahir UI"
          }
        ]
      },
      
      # Search
      {
        element: "div",
        className: "search-container",
        children: [
          {
            element: "input",
            className: "search-input",
            placeholder: "Enter city name",
            value: state.city,
            onChange: handleInputChange
          },
          {
            element: "button",
            className: "search-button",
            content: "Search",
            onClick: handleSearch
          }
        ]
      },
      
      # Content
      {
        element: "div",
        className: "weather-content",
        children: state.loading ? [
          # Loading state
          {
            element: "div",
            className: "loading",
            content: "Loading weather data..."
          }
        ] : state.error ? [
          # Error state
          {
            element: "div",
            className: "error",
            content: state.error
          }
        ] : [
          # Current weather
          {
            element: "div",
            className: "current-weather",
            children: [
              {
                element: "div",
                className: "weather-icon",
                children: [
                  {
                    element: "i",
                    className: "fas " + state.currentWeather.icon
                  }
                ]
              },
              {
                element: "h2",
                className: "temperature",
                content: Math.round(state.currentWeather.temperature) + "°F"
              },
              {
                element: "p",
                className: "weather-description",
                content: state.currentWeather.condition
              },
              {
                element: "p",
                className: "location",
                content: state.currentWeather.location
              },
              {
                element: "div",
                className: "weather-details",
                children: [
                  # Humidity
                  {
                    element: "div",
                    className: "weather-detail",
                    children: [
                      {
                        element: "span",
                        className: "detail-label",
                        content: "Humidity"
                      },
                      {
                        element: "span",
                        className: "detail-value",
                        content: state.currentWeather.humidity + "%"
                      }
                    ]
                  },
                  # Wind
                  {
                    element: "div",
                    className: "weather-detail",
                    children: [
                      {
                        element: "span",
                        className: "detail-label",
                        content: "Wind"
                      },
                      {
                        element: "span",
                        className: "detail-value",
                        content: state.currentWeather.wind + " mph"
                      }
                    ]
                  },
                  # Pressure
                  {
                    element: "div",
                    className: "weather-detail",
                    children: [
                      {
                        element: "span",
                        className: "detail-label",
                        content: "Pressure"
                      },
                      {
                        element: "span",
                        className: "detail-value",
                        content: state.currentWeather.pressure + " hPa"
                      }
                    ]
                  },
                  # UV Index
                  {
                    element: "div",
                    className: "weather-detail",
                    children: [
                      {
                        element: "span",
                        className: "detail-label",
                        content: "UV Index"
                      },
                      {
                        element: "span",
                        className: "detail-value",
                        content: state.currentWeather.uv
                      }
                    ]
                  }
                ]
              }
            ]
          },
          
          # Forecast
          {
            element: "div",
            className: "forecast",
            children: state.forecast.map(function(day) {
              return {
                element: "div",
                className: "forecast-day",
                children: [
                  {
                    element: "div",
                    className: "forecast-date",
                    content: day.date
                  },
                  {
                    element: "div",
                    className: "forecast-icon",
                    children: [
                      {
                        element: "i",
                        className: "fas " + day.icon
                      }
                    ]
                  },
                  {
                    element: "div",
                    className: "forecast-temp",
                    children: [
                      {
                        element: "span",
                        className: "forecast-high",
                        content: Math.round(day.highTemp) + "°"
                      },
                      {
                        element: "span",
                        className: "forecast-low",
                        content: Math.round(day.lowTemp) + "°"
                      }
                    ]
                  }
                ]
              }
            })
          },
          
          # Weather Map
          {
            element: "div",
            className: "weather-map",
            content: "Weather Map (Placeholder)"
          }
        ]
      }
    ]
  }
}

# Create and render the Weather Dashboard
dashboard = WeatherDashboard.new()
dashboard.init()
UI.render(dashboard)

How It Works

The Weather Dashboard is built using a single main component that handles all the functionality:

Key Features

  • API Integration: The app fetches weather data from a weather API service.
  • Data Caching: Weather data is cached in K2's ramdisk cache to reduce API calls and improve performance.
  • Conditional Rendering: The UI adapts based on loading state, errors, and available data.
  • Search Functionality: Users can search for weather in different cities.
  • Weather Icons: The app maps weather condition codes to appropriate icons.

Performance Optimizations

The Weather Dashboard uses several performance optimizations:

  • Ramdisk Caching: Weather data is cached in ramdisk for microsecond access times.
  • Cache Invalidation: Cached data is only used if it's less than 1 hour old.
  • Conditional Rendering: Only necessary components are rendered based on the application state.
  • Efficient Data Processing: Weather data is processed and transformed once, then cached.

Cache Implementation

The caching system works as follows:

  1. When fetching weather data, the app first checks if data for the requested city exists in the cache.
  2. If cached data exists and is less than 1 hour old, it's used instead of making an API call.
  3. If no cached data exists or it's stale, the app fetches fresh data from the API.
  4. After fetching new data, it's processed and stored in the cache with a timestamp.

This approach significantly reduces API calls and improves application performance, especially for frequently accessed cities.

Running This Example

To run this example on your machine:

  1. Install K2 language: curl -sSL https://k2lang.org/install | bash
  2. Install Nahir UI: k2 install nahir-ui
  3. Save the code above as weather_app.k2
  4. Replace your_api_key_here with a valid API key from WeatherAPI.com
  5. Run the application: k2 weather_app.k2

The application will open in a window, or if you're in a terminal-only environment, it will render as text UI.

Ready to Build Your Own Nahir UI App?

Get started with Nahir UI and build ultra-fast user interfaces for your K2 applications.