summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsiddharth <s@ricketyspace.net>2022-05-21 20:58:34 -0400
committersiddharth <s@ricketyspace.net>2022-05-21 20:58:34 -0400
commit5559bf37e05244e97020c4fbe77646e17ae42085 (patch)
tree1c50c2043fc0884077efd4dac7f8eead78492222
parent7afe0925dbd6905cb3b64b72181c9f04c8ff7be1 (diff)
peach: flesh out bare bones
-rw-r--r--html/weather.html42
-rw-r--r--main.go135
-rw-r--r--static/peach.css15
3 files changed, 191 insertions, 1 deletions
diff --git a/html/weather.html b/html/weather.html
new file mode 100644
index 0000000..520c284
--- /dev/null
+++ b/html/weather.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>peach</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="author" content="siddharth">
+ <link rel="preload" href="/static/peach.css" as="style" />
+ <style>@import url("/static/peach.css");</style>
+</head>
+<body>
+ <div class="peach-container">
+ <div class="location block">
+ <p>{{.Location}}</p>
+ </div>
+
+ <div class="summary">
+ <div class="now">
+ <p class="forecast">{{.Now.Forecast}}</p>
+ <p class="tempature">{{.Now.Temperature}}{{.Now.TemperatureUnit}}</p>
+ <p class="wind">{{.Now.WindSpeed}} {{.Now.WindDirection}}</p>
+ </div>
+ <div class="current-period">
+ <p class="forecast">{{.Period.Forecast}}</p>
+ </div>
+ </div>
+
+ {{ if .Timeline }}
+ <div class="timeline">
+ <div class="container">
+ {{ range .Timeline.Periods }}
+ <div class="period">
+ <p class="temperature">{{.Temperature}}{{.TemperatureUnit}}</p>
+ <p class="hour">{{printf "%d" .Hour}}hrs</p>
+ </div>
+ {{ end }}
+ </div>
+ </div>
+ {{ end }}
+
+ </div>
+</body>
diff --git a/main.go b/main.go
index b0fd29a..2f4448e 100644
--- a/main.go
+++ b/main.go
@@ -3,4 +3,137 @@
package main
-func main() {}
+import (
+ "embed"
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+ "time"
+
+ "ricketyspace.net/peach/nws"
+)
+
+// Holds static content.
+//go:embed html static
+var peachFS embed.FS
+
+// HTML templates.
+var peachTemplates = template.Must(template.ParseFS(peachFS, "html/*.html"))
+
+type Weather struct {
+ Location string
+ Now WeatherNow
+ Period WeatherPeriod
+ Timeline WeatherTimeline
+}
+
+type WeatherNow struct {
+ Temperature int
+ TemperatureUnit string
+ Forecast string
+ WindSpeed string
+ WindDirection string
+}
+
+type WeatherPeriod struct {
+ Forecast string
+ Hour int
+ Temperature int
+ TemperatureUnit string
+}
+
+type WeatherTimeline struct {
+ Periods []WeatherPeriod
+}
+
+func main() {
+ http.Handle("/static/", http.FileServer(http.FS(peachFS)))
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ if len(r.URL.Path[1:]) != 0 {
+ http.NotFound(w, r)
+ return
+ }
+ showWeather(w, 41.115, -83.177)
+ })
+ log.Fatal(http.ListenAndServe(":8151", nil))
+}
+
+func showWeather(w http.ResponseWriter, lat, lng float32) {
+ point, err := nws.Points(lat, lng)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+
+ // Get forecast
+ f, err := nws.Forecast(point)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+ fh, err := nws.ForecastHourly(point)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+
+ // Make weather
+ weather, err := NewWeather(point, f, fh)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+
+ err = peachTemplates.ExecuteTemplate(w, "weather.html", weather)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+}
+
+func NewWeather(point *nws.NWSPoint, f, fh *nws.NWSForecast) (*Weather, error) {
+ w := new(Weather)
+ w.Location = fmt.Sprintf("%s, %s",
+ point.Properties.RelativeLocation.Properties.City,
+ point.Properties.RelativeLocation.Properties.State,
+ )
+ w.Now = WeatherNow{
+ Temperature: fh.Properties.Periods[0].Temperature,
+ TemperatureUnit: fh.Properties.Periods[0].TemperatureUnit,
+ Forecast: fh.Properties.Periods[0].ShortForecast,
+ WindSpeed: fh.Properties.Periods[0].WindSpeed,
+ WindDirection: fh.Properties.Periods[0].WindDirection,
+ }
+ w.Period = WeatherPeriod{
+ Forecast: f.Properties.Periods[0].DetailedForecast,
+ }
+
+ // Build timeline.
+ periods := []WeatherPeriod{}
+ max := 12
+ for i, period := range fh.Properties.Periods {
+ if i%2 != 0 {
+ continue // Take every other period
+ }
+ t, err := time.Parse(time.RFC3339, period.StartTime)
+ if err != nil {
+ return nil, err
+ }
+ p := WeatherPeriod{
+ Forecast: period.DetailedForecast,
+ Hour: t.Hour(),
+ Temperature: period.Temperature,
+ TemperatureUnit: period.TemperatureUnit,
+ }
+ periods = append(periods, p)
+ if len(periods) == max {
+ break
+ }
+ }
+ w.Timeline = WeatherTimeline{
+ Periods: periods,
+ }
+
+ return w, nil
+}
diff --git a/static/peach.css b/static/peach.css
new file mode 100644
index 0000000..6d32955
--- /dev/null
+++ b/static/peach.css
@@ -0,0 +1,15 @@
+p {
+ margin: 0;
+}
+
+.peach-container {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+}
+
+.timeline .container {
+ display: flex;
+ justify-content: space-around;
+ align-content: space-around;
+}