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 }}