Live update Reveal config

This commit is contained in:
Peter 2021-12-22 20:19:05 +01:00
parent 82a651cd5d
commit 3f847e0b8b
Signed by: prskr
GPG key ID: C1DB5D2E8DB512F9
5 changed files with 89 additions and 60 deletions

View file

@ -51,8 +51,8 @@ var (
hub := events.NewEventHub( hub := events.NewEventHub(
wdfs, wdfs,
fnv.New32a(), fnv.New32a(),
events.FileNameTrigger(args[0]), events.MutationReloadForFile(args[0]),
events.FileNameTrigger(filepath.Base(cfg.ConfigFileInUse)), events.MutationConfigReloadForFile(filepath.Base(cfg.ConfigFileInUse)),
) )
api.NoCache(app) api.NoCache(app)

View file

@ -3,9 +3,10 @@ package config
var ( var (
defaults = map[string]interface{}{ defaults = map[string]interface{}{
"mermaid.theme": "forest", "mermaid.theme": "forest",
"reveal.theme": "beige", "theme": "beige",
"codeTheme": "monokai", "codeTheme": "monokai",
"transition": TransitionNone, "transition": TransitionNone,
"controlsLayout": ControlsLayoutEdges,
"controls": true, "controls": true,
"progress": true, "progress": true,
"history": true, "history": true,
@ -23,11 +24,15 @@ const (
TransitionConvex Transition = "convex" TransitionConvex Transition = "convex"
TransitionConcave Transition = "concave" TransitionConcave Transition = "concave"
TransitionZoom Transition = "zoom" TransitionZoom Transition = "zoom"
ControlsLayoutBottomRight ControlsLayout = "bottom-right"
ControlsLayoutEdges ControlsLayout = "edges"
) )
type ( type (
Transition string Transition string
Mermaid struct { ControlsLayout string
Mermaid struct {
Theme string `json:"theme"` Theme string `json:"theme"`
} }
Rendering struct { Rendering struct {
@ -36,15 +41,16 @@ type (
Stylesheets []string Stylesheets []string
} }
Reveal struct { Reveal struct {
Theme string `json:"theme"` Theme string `json:"theme"`
CodeTheme string `json:"codeTheme"` CodeTheme string `json:"codeTheme"`
Transition Transition `json:"transition"` Transition Transition `json:"transition"`
Controls bool `json:"controls"` Controls bool `json:"controls"`
Progress bool `json:"progress"` ControlsLayout ControlsLayout `json:"controlsLayout"`
History bool `json:"history"` Progress bool `json:"progress"`
Center bool `json:"center"` History bool `json:"history"`
SlideNumber bool `json:"slideNumber"` Center bool `json:"center"`
Menu struct { SlideNumber bool `json:"slideNumber"`
Menu struct {
Numbers bool `json:"numbers"` Numbers bool `json:"numbers"`
UseTextContentForMissingTitles bool `json:"useTextContentForMissingTitles"` UseTextContentForMissingTitles bool `json:"useTextContentForMissingTitles"`
Transitions bool Transitions bool

View file

@ -21,14 +21,15 @@ const (
) )
type ( type (
ReloadTrigger interface { EventMutation interface {
Triggers(ev fs.Event) bool OnEvent(in ContentEvent, ev fs.Event) (out ContentEvent)
} }
ContentEvent struct { ContentEvent struct {
File string `json:"file"` File string `json:"file"`
FileNameHash string `json:"fileNameHash"` FileNameHash string `json:"fileNameHash"`
Timestamp string `json:"ts"` Timestamp string `json:"ts"`
ForceReload bool `json:"forceReload"` ForceReload bool `json:"forceReload"`
ReloadConfig bool `json:"reloadConfig"`
} }
EventSource interface { EventSource interface {
io.Closer io.Closer
@ -43,30 +44,35 @@ type (
EventHandler EventHandler
OnError chan error OnError chan error
} }
FileNameTrigger string MutationReloadForFile string
FileSuffixTrigger string MutationConfigReloadForFile string
) )
func (t FileNameTrigger) Triggers(ev fs.Event) bool { func (t MutationReloadForFile) OnEvent(in ContentEvent, ev fs.Event) (out ContentEvent) {
fileBase := filepath.Base(ev.File) if strings.EqualFold(filepath.Base(ev.File), string(t)) {
return strings.EqualFold(fileBase, string(t)) in.ForceReload = true
}
return in
} }
func (t FileSuffixTrigger) Triggers(ev fs.Event) bool { func (t MutationConfigReloadForFile) OnEvent(in ContentEvent, ev fs.Event) (out ContentEvent) {
return strings.HasSuffix(strings.ToLower(filepath.Base(ev.File)), strings.ToLower(string(t))) if strings.EqualFold(filepath.Base(ev.File), string(t)) {
in.ReloadConfig = true
}
return in
} }
func (f EventHandlerFunc) OnEvent(ev ContentEvent) error { func (f EventHandlerFunc) OnEvent(ev ContentEvent) error {
return f(ev) return f(ev)
} }
func NewEventHub(eventSource EventSource, fileNameHash hash.Hash, triggers ...ReloadTrigger) *EventHub { func NewEventHub(eventSource EventSource, fileNameHash hash.Hash, mutations ...EventMutation) *EventHub {
hub := &EventHub{ hub := &EventHub{
FileNameHash: fileNameHash, FileNameHash: fileNameHash,
reloadTriggers: triggers, mutations: mutations,
source: eventSource, source: eventSource,
subscriptions: make(map[uuid.UUID]*subscription), subscriptions: make(map[uuid.UUID]*subscription),
done: make(chan struct{}), done: make(chan struct{}),
} }
go hub.processEvents() go hub.processEvents()
@ -75,12 +81,12 @@ func NewEventHub(eventSource EventSource, fileNameHash hash.Hash, triggers ...Re
} }
type EventHub struct { type EventHub struct {
FileNameHash hash.Hash FileNameHash hash.Hash
reloadTriggers []ReloadTrigger mutations []EventMutation
lock sync.RWMutex lock sync.RWMutex
done chan struct{} done chan struct{}
source EventSource source EventSource
subscriptions map[uuid.UUID]*subscription subscriptions map[uuid.UUID]*subscription
} }
func (h *EventHub) Subscribe(handler EventHandler) (id uuid.UUID, onError <-chan error) { func (h *EventHub) Subscribe(handler EventHandler) (id uuid.UUID, onError <-chan error) {
@ -129,20 +135,16 @@ func (h *EventHub) notifySubscribers(ev fs.Event) {
h.lock.RLock() h.lock.RLock()
defer h.lock.RUnlock() defer h.lock.RUnlock()
var triggerReload bool
for idx := range h.reloadTriggers {
if triggerReload = h.reloadTriggers[idx].Triggers(ev); triggerReload {
break
}
}
ce := ContentEvent{ ce := ContentEvent{
File: fmt.Sprintf("/%s", ev.File), File: fmt.Sprintf("/%s", ev.File),
Timestamp: strconv.FormatInt(ev.Timestamp.Unix(), baseDecimal), Timestamp: strconv.FormatInt(ev.Timestamp.Unix(), baseDecimal),
ForceReload: triggerReload,
FileNameHash: hex.EncodeToString(h.FileNameHash.Sum([]byte(path.Base(ev.File)))), FileNameHash: hex.EncodeToString(h.FileNameHash.Sum([]byte(path.Base(ev.File)))),
} }
for idx := range h.mutations {
ce = h.mutations[idx].OnEvent(ce, ev)
}
for _, handler := range h.subscriptions { for _, handler := range h.subscriptions {
if err := handler.OnEvent(ce); err != nil { if err := handler.OnEvent(ce); err != nil {
handler.OnError <- err handler.OnError <- err

View file

@ -3,6 +3,16 @@ codeTheme: monokai
horizontalSeparator: === horizontalSeparator: ===
verticalSeparator: --- verticalSeparator: ---
transition: convex transition: convex
menu.numbers: false controlsLayout: edges
controls: true
progress: true
history: true
center: true
slideNumber: true
menu:
numbers: false
useTextContentForMissingTitles: true
mermaid:
theme: forest
stylesheets: stylesheets:
- custom.css - custom.css

View file

@ -25,9 +25,13 @@ async function setSlidesContent() {
document.getElementById("content-root").innerHTML = contentDocument.documentElement.innerHTML document.getElementById("content-root").innerHTML = contentDocument.documentElement.innerHTML
} }
async function initReveal() { async function getRevealConfig() {
let resp = await fetch('/api/v1/config/reveal') let resp = await fetch('/api/v1/config/reveal')
let cfg = await resp.json() return await resp.json()
}
async function initReveal() {
let cfg = await getRevealConfig()
Reveal.initialize({ Reveal.initialize({
controls: cfg.controls, controls: cfg.controls,
progress: cfg.progress, progress: cfg.progress,
@ -97,20 +101,27 @@ function subscribeToEvents() {
source.onmessage = (ev => { source.onmessage = (ev => {
let obj = JSON.parse(ev.data); let obj = JSON.parse(ev.data);
console.log(obj); console.log(obj);
if (obj.forceReload) { switch (true) {
window.location.reload() case obj.forceReload:
} else { window.location.reload()
switch (true) { break
case obj.file.endsWith(".css"): case obj.reloadConfig:
let cssLink = document.querySelector(`link[rel=stylesheet][id="${obj.fileNameHash}"]`); getRevealConfig().then(cfg => {
cssLink.href = `${obj.file}?ts=${obj.ts}` Reveal.configure(cfg)
break })
default: break
let elem = document.getElementById(obj.fileNameHash); default:
if (elem !== null) { switch (true) {
elem.src = `${obj.file}?ts=${obj.ts}` case obj.file.endsWith(".css"):
} let cssLink = document.querySelector(`link[rel=stylesheet][id="${obj.fileNameHash}"]`);
} cssLink.href = `${obj.file}?ts=${obj.ts}`
break
default:
let elem = document.getElementById(obj.fileNameHash);
if (elem !== null) {
elem.src = `${obj.file}?ts=${obj.ts}`
}
}
} }
}) })
} }