Create a basic HTML page to permit usage of non-JS devices
This commit is contained in:
parent
fa13484718
commit
7df46e03e0
1
app.go
1
app.go
@ -49,6 +49,7 @@ func NewApp(cfg *config.Config) *App {
|
||||
|
||||
// Register routes
|
||||
ui.DeclareRoutes(router, cfg)
|
||||
ui.DeclareNoJSRoutes(router, cfg, db, app.ResetTimer)
|
||||
api.DeclareRoutes(router, cfg, db, app.ResetTimer)
|
||||
|
||||
router.GET("/api/version", func(c *gin.Context) {
|
||||
|
139
ui/nojs.go
Normal file
139
ui/nojs.go
Normal file
@ -0,0 +1,139 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"git.nemunai.re/nemunaire/reveil/config"
|
||||
"git.nemunai.re/nemunaire/reveil/model"
|
||||
"git.nemunai.re/nemunaire/reveil/player"
|
||||
)
|
||||
|
||||
//go:embed nojs_templates/*
|
||||
var nojs_tpl embed.FS
|
||||
|
||||
func DeclareNoJSRoutes(router *gin.Engine, cfg *config.Config, db *reveil.LevelDBStorage, resetTimer func()) {
|
||||
templ := template.Must(template.New("").ParseFS(nojs_tpl, "nojs_templates/*.tmpl"))
|
||||
router.SetHTMLTemplate(templ)
|
||||
|
||||
router.GET("/nojs.html", func(c *gin.Context) {
|
||||
alarm, err := reveil.GetNextAlarm(cfg, db)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
nCycles := int(time.Until(*alarm) / (90 * time.Minute))
|
||||
nDays := int(time.Until(*alarm) / (24 * time.Hour))
|
||||
nMinutes := int((time.Until(*alarm) / time.Minute) % 90)
|
||||
|
||||
c.HTML(http.StatusOK, "index.tmpl", gin.H{
|
||||
"nextAlarmDate": alarm.Format("Mon 2"),
|
||||
"nextAlarmTime": alarm.Format("15:04"),
|
||||
"sameDay": time.Now().Day() == alarm.Day(),
|
||||
"nCycles": nCycles,
|
||||
"nDays": nDays,
|
||||
"nMinutes": nMinutes,
|
||||
"isPlaying": player.CommonPlayer != nil,
|
||||
})
|
||||
})
|
||||
|
||||
router.POST("/nojs.html", func(c *gin.Context) {
|
||||
var form struct {
|
||||
Action string `form:"action"`
|
||||
Time *string `form:"time"`
|
||||
}
|
||||
c.Bind(&form)
|
||||
|
||||
switch form.Action {
|
||||
case "new":
|
||||
if form.Time == nil {
|
||||
c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"errmsg": "This time is invalid."})
|
||||
return
|
||||
}
|
||||
|
||||
alarm := time.Now()
|
||||
|
||||
if len(*form.Time) == 2 && (*form.Time)[1] == 'c' {
|
||||
n, err := strconv.Atoi((*form.Time)[:1])
|
||||
if err != nil {
|
||||
c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"errmsg": fmt.Sprintf("This number of cycle is invalid: %s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
alarm = alarm.Add((time.Duration(90*n) + 10) * time.Minute)
|
||||
} else {
|
||||
tmp := strings.Split(*form.Time, ":")
|
||||
if len(tmp) != 2 {
|
||||
c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"errmsg": "This time is invalid."})
|
||||
return
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(fmt.Sprintf("%sh%sm", tmp[0], tmp[1]))
|
||||
if err != nil {
|
||||
c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"errmsg": fmt.Sprintf("This time is invalid: %s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
_, offset := alarm.Zone()
|
||||
alarm = alarm.Truncate(24 * time.Hour).Add(-time.Duration(offset)*time.Second + duration)
|
||||
}
|
||||
|
||||
if time.Now().After(alarm) {
|
||||
alarm = alarm.Add(24 * time.Hour)
|
||||
}
|
||||
|
||||
if err := reveil.PutAlarmSingle(db, &reveil.AlarmSingle{
|
||||
Time: alarm,
|
||||
}); err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
resetTimer()
|
||||
|
||||
case "cancel":
|
||||
err := reveil.DropNextAlarm(cfg, db)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
resetTimer()
|
||||
|
||||
case "start":
|
||||
if player.CommonPlayer == nil {
|
||||
err := player.WakeUp(cfg)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"errmsg": "Player already running"})
|
||||
return
|
||||
}
|
||||
|
||||
case "nexttrack":
|
||||
if player.CommonPlayer != nil {
|
||||
player.CommonPlayer.NextTrack()
|
||||
}
|
||||
|
||||
case "stop":
|
||||
if player.CommonPlayer != nil {
|
||||
err := player.CommonPlayer.Stop()
|
||||
if err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusFound, "/nojs.html")
|
||||
})
|
||||
}
|
4
ui/nojs_templates/error.tmpl
Normal file
4
ui/nojs_templates/error.tmpl
Normal file
@ -0,0 +1,4 @@
|
||||
<h1>
|
||||
Une erreur inattendue s'est produite :
|
||||
{{ .errmsg }}
|
||||
</h1>
|
73
ui/nojs_templates/index.tmpl
Normal file
73
ui/nojs_templates/index.tmpl
Normal file
@ -0,0 +1,73 @@
|
||||
<h1 style="margin-bottom: 0">
|
||||
Prochain réveil le :
|
||||
{{ if .sameDay }}
|
||||
aujourd'hui
|
||||
{{ else if lt .nCycles 16 }}
|
||||
demain
|
||||
{{ else }}
|
||||
{{ .nextAlarmDate }}
|
||||
{{ end }}
|
||||
à {{ .nextAlarmTime }}
|
||||
</h1>
|
||||
<h2 style="color: gray; margin-top: 0; margin-left: 5em">
|
||||
{{ if gt .nDays 2 }}(dans {{ .nDays }} jours){{ else }}(dans {{ .nCycles }} cycles + {{ .nMinutes }} min){{ end }}
|
||||
</h2>
|
||||
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="cancel">
|
||||
<button type="submit">
|
||||
Annuler la prochaine alarme
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{{ if .isPlaying }}
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="stop">
|
||||
<button type="submit">
|
||||
Arrêter le réveil
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="nexttrack">
|
||||
<button type="submit">
|
||||
Prochaine musique
|
||||
</button>
|
||||
</form>
|
||||
{{ else }}
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="start">
|
||||
<button type="submit">
|
||||
Lancer le réveil
|
||||
</button>
|
||||
</form>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<h3>Programmer une nouvelle alarme</h3>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="new">
|
||||
<input type="time" required name="time">
|
||||
<button type="submit">
|
||||
Nouvelle alarme
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="new">
|
||||
<input type="hidden" name="time" value="5c">
|
||||
<button type="submit">
|
||||
+ 5 cycles
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form method="post" action="/nojs.html">
|
||||
<input type="hidden" name="action" value="new">
|
||||
<input type="hidden" name="time" value="6c">
|
||||
<button type="submit">
|
||||
+ 6 cycles
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
18
ui/nojs_templates/single.tmpl
Normal file
18
ui/nojs_templates/single.tmpl
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr" class="d-flex flex-column mh-100 h-100">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="theme-color" content="#ffffff"/>
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/img/apple-touch-icon.png">
|
||||
<meta name="author" content="nemucorp">
|
||||
<meta name="robots" content="none">
|
||||
<base href="/">
|
||||
</head>
|
||||
<body class="flex-fill d-flex flex-column">
|
||||
<div class="flex-fill d-flex flex-column justify-content-between" style="min-height: 100%">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
@ -14,6 +14,7 @@
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body class="flex-fill d-flex flex-column">
|
||||
<noscript>Si la page ne charge pas, essayez <a href="/nojs.html">la version sans JavaScript</a>.</noscript>
|
||||
<div class="flex-fill d-flex flex-column justify-content-between" style="min-height: 100%">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
0
ui/src/routes/nojs/+page.svelte
Normal file
0
ui/src/routes/nojs/+page.svelte
Normal file
Loading…
x
Reference in New Issue
Block a user