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
|
// Register routes
|
||||||
ui.DeclareRoutes(router, cfg)
|
ui.DeclareRoutes(router, cfg)
|
||||||
|
ui.DeclareNoJSRoutes(router, cfg, db, app.ResetTimer)
|
||||||
api.DeclareRoutes(router, cfg, db, app.ResetTimer)
|
api.DeclareRoutes(router, cfg, db, app.ResetTimer)
|
||||||
|
|
||||||
router.GET("/api/version", func(c *gin.Context) {
|
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%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body class="flex-fill d-flex flex-column">
|
<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>
|
<div class="flex-fill d-flex flex-column justify-content-between" style="min-height: 100%">%sveltekit.body%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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