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(
wdfs,
fnv.New32a(),
events.FileNameTrigger(args[0]),
events.FileNameTrigger(filepath.Base(cfg.ConfigFileInUse)),
events.MutationReloadForFile(args[0]),
events.MutationConfigReloadForFile(filepath.Base(cfg.ConfigFileInUse)),
)
api.NoCache(app)

View file

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

View file

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

View file

@ -3,6 +3,16 @@ codeTheme: monokai
horizontalSeparator: ===
verticalSeparator: ---
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:
- custom.css

View file

@ -25,9 +25,13 @@ async function setSlidesContent() {
document.getElementById("content-root").innerHTML = contentDocument.documentElement.innerHTML
}
async function initReveal() {
async function getRevealConfig() {
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({
controls: cfg.controls,
progress: cfg.progress,
@ -97,20 +101,27 @@ function subscribeToEvents() {
source.onmessage = (ev => {
let obj = JSON.parse(ev.data);
console.log(obj);
if (obj.forceReload) {
window.location.reload()
} else {
switch (true) {
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}`
}
}
switch (true) {
case obj.forceReload:
window.location.reload()
break
case obj.reloadConfig:
getRevealConfig().then(cfg => {
Reveal.configure(cfg)
})
break
default:
switch (true) {
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}`
}
}
}
})
}