diff --git a/dashboard.go b/dashboard.go
new file mode 100644
index 0000000..fed531a
--- /dev/null
+++ b/dashboard.go
@@ -0,0 +1,20 @@
+package main
+
+type WidgetType int
+
+const (
+ WidgetLabel WidgetType = iota
+ WidgetOnOff
+)
+
+type Widget struct {
+ Type WidgetType
+ X int
+ Y int
+ DatapointID int
+ Attributes map[string]string
+}
+
+type Dashboard struct {
+ Widgets []Widget
+}
diff --git a/main.go b/main.go
index d6f81cd..80a1638 100644
--- a/main.go
+++ b/main.go
@@ -405,6 +405,17 @@ func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
PAGE: "index",
CONFIG: smonConfig.Settings,
}
+
+ data := make(map[string]any)
+ data["Dashboard"] = Dashboard{
+ Widgets: []Widget{
+ {Type: 0, X: 1, Y: 1, Attributes: map[string]string{"Label":"Services"}},
+
+ {Type: 1, X: 1, Y: 2, DatapointID: 13, Attributes: map[string]string{"Label":"Borg"}},
+ {Type: 1, X: 1, Y: 3, DatapointID: 13, Attributes: map[string]string{"Label":"Databasus"}},
+ },
+ }
+ page.Data = data
page.Render(w, r)
} // }}}
diff --git a/static/css/gruvbox/gruvbox.css b/static/css/gruvbox/gruvbox.css
index 6acdbc0..e041022 100644
--- a/static/css/gruvbox/gruvbox.css
+++ b/static/css/gruvbox/gruvbox.css
@@ -1,5 +1,5 @@
body {
- background-image: url(/images/v0/gruvbox/background.svg);
+ /* background-image: url(/images/v0/gruvbox/background.svg); */
}
#menu {
box-shadow: 2px 0px 5px 3px rgba(0, 0, 0, 0.25);
diff --git a/static/images/widget_light_green.svg b/static/images/widget_light_green.svg
new file mode 100644
index 0000000..a0bc5a5
--- /dev/null
+++ b/static/images/widget_light_green.svg
@@ -0,0 +1,49 @@
+
+
+
+
diff --git a/static/images/widget_light_off.svg b/static/images/widget_light_off.svg
new file mode 100644
index 0000000..bcaed9f
--- /dev/null
+++ b/static/images/widget_light_off.svg
@@ -0,0 +1,49 @@
+
+
+
+
diff --git a/static/images/widget_light_red.svg b/static/images/widget_light_red.svg
new file mode 100644
index 0000000..11a7e9d
--- /dev/null
+++ b/static/images/widget_light_red.svg
@@ -0,0 +1,49 @@
+
+
+
+
diff --git a/static/js/dashboard.mjs b/static/js/dashboard.mjs
new file mode 100644
index 0000000..29d151a
--- /dev/null
+++ b/static/js/dashboard.mjs
@@ -0,0 +1,137 @@
+import { CustomHTMLElement } from './lib/custom_html_element.mjs'
+
+export class SmonDashboard extends CustomHTMLElement {
+ static {
+ this.tmpl = document.createElement('template')
+ this.tmpl.innerHTML = `
+
+
+
+
+ `
+ }
+ constructor() {
+ super(true)
+ const script = this.querySelector('script')
+ this.data = JSON.parse(script.textContent)
+ this.render()
+ }
+
+ render() {
+ const widgets = []
+ for (const wd of this.data.Widgets) {
+ const widget = SmonWidget.create(wd.Type, wd)
+ widgets.push(widget)
+ }
+ this.elGrid.replaceChildren(...widgets)
+ }
+}
+
+class SmonWidget extends CustomHTMLElement {
+ static create(t, data) {
+ switch (t) {
+ case 0: return new SmonWidgetLabel(data)
+ case 1: return new SmonWidgetOnOff(data)
+ }
+ }
+
+ constructor(data) {
+ super(true)
+ this.data = data
+ }
+
+ render() {
+ this.style.gridColumn = this.data.X
+ this.style.gridRow = this.data.Y
+ }
+}
+
+class SmonWidgetLabel extends SmonWidget {
+ static {
+ this.tmpl = document.createElement('template')
+ this.tmpl.innerHTML = `
+
+
+ `
+ }
+
+ constructor(data) {
+ super(data)
+ this.render()
+ }
+
+ render() {
+ super.render()
+ this.elLabel.innerText = this.data.Attributes?.Label || '[set Label]'
+ }
+}
+
+class SmonWidgetOnOff extends SmonWidget {
+ static {
+ this.tmpl = document.createElement('template')
+ this.tmpl.innerHTML = `
+
+
+
+ `
+ }
+
+ constructor(data) {
+ super(data)
+ this.render()
+ }
+
+ render() {
+ super.render()
+
+ let img
+ switch (this.data.Attributes.Status) {
+ case 'ON':
+ img = 'widget_light_green.svg'
+ break
+
+ case 'OFF':
+ img = 'widget_light_red.svg'
+ break
+
+ default:
+ img = 'widget_light_off.svg'
+ }
+
+ this.elStatus.setAttribute('src', `/images/${_VERSION}/${img}`)
+ this.elLabel.innerText = this.data.Attributes.Label
+ }
+}
+
+
+customElements.define("smon-widget", SmonWidget)
+customElements.define("smon-widget-label", SmonWidgetLabel)
+customElements.define("smon-widget-onoff", SmonWidgetOnOff)
+customElements.define("smon-dashboard", SmonDashboard)
diff --git a/static/js/lib/custom_html_element.mjs b/static/js/lib/custom_html_element.mjs
new file mode 100644
index 0000000..d1fb7ae
--- /dev/null
+++ b/static/js/lib/custom_html_element.mjs
@@ -0,0 +1,51 @@
+/* Use data-el or data-field attribute.
+ * Element with data-el="hum-ding" is accessible as this.elHumDing and fields with
+ * data-field="long-dong" as this.fieldLongDong.
+ *
+ * All field values can be retrieved with fieldValues() and uses the data-field attribute
+ * as LongDong as key.
+ */
+
+export class CustomHTMLElement extends HTMLElement {
+ constructor(useShadow) {// {{{
+ super()
+
+ this._fields = new Map()
+
+ const workOn = useShadow ? this.attachShadow({ mode: 'open' }) : this
+ workOn.appendChild(this.constructor.tmpl.content.cloneNode(true))
+ workOn.querySelectorAll('*').forEach(el => {
+ const field = el.dataset.field
+ if (field !== undefined) {
+ const fieldName = this.toElementName('field', field)
+ this[fieldName] = el
+ this._fields.set(this.toElementName('', field), el)
+ }
+
+ const name = el.dataset.el
+ if (name !== undefined) {
+ const elName = this.toElementName('el', name)
+ this[elName] = el
+ el.classList.add('el-' + name)
+ }
+ })
+ }// }}}
+ allFields() {// {{{
+ return this._fields
+ }// }}}
+ fieldValues() {// {{{
+ const state = {}
+ for (const [name, field] of this._fields) {
+ if (field.tagName.toLowerCase() == 'input' && field.getAttribute('type').toLowerCase() == 'checkbox')
+ state[name] = field.checked
+ else
+ state[name] = field.value
+
+ }
+ return state
+ }// }}}
+ toElementName(prefix, str) {// {{{
+ str = prefix + '-' + str
+ return str.replace(/-(id|[a-z])/g, match => match.toUpperCase().replace('-', ''))
+ }// }}}
+}
diff --git a/views/layouts/main.gotmpl b/views/layouts/main.gotmpl
index b82b49f..263d61f 100644
--- a/views/layouts/main.gotmpl
+++ b/views/layouts/main.gotmpl
@@ -6,6 +6,9 @@
{{ template "fonts" }}
+
diff --git a/views/pages/index.gotmpl b/views/pages/index.gotmpl
index f5d7056..bae426f 100644
--- a/views/pages/index.gotmpl
+++ b/views/pages/index.gotmpl
@@ -1,13 +1,21 @@
{{ define "page" }}
-
+
+
+
-
+
SMon
{{ .VERSION }}
+
+
+
+
{{ end }}