From c6d868b2438054cb2d25aa31c0c1696ea88ce6aa Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 23:04:31 +0200 Subject: [PATCH] [task-408] [mod] Quellen-Steuerelement umgestellt --- source/data/localization/deu.loc.json | 1 + source/data/localization/eng.loc.json | 1 + source/pages/overview/logic.ts | 22 +- source/style/main.css | 6 +- source/style/widget-sources.css | 6 +- source/widgets/sources/logic.ts | 326 +++++++++++------- .../widgets/sources/templates/main.html.tpl | 9 +- 7 files changed, 233 insertions(+), 138 deletions(-) diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 52bdc5b..dfc7be8 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -55,6 +55,7 @@ "widget.event_edit.actions.add": "anlegen", "widget.event_edit.actions.change": "ändern", "widget.event_edit.actions.remove": "löschen", + "widget.sources.create": "anlegen", "page.login.title": "Anmelden", "page.login.internal.name": "Name", "page.login.internal.password": "Kennwort", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 023e8d2..4daaa92 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -55,6 +55,7 @@ "widget.event_edit.actions.add": "add", "widget.event_edit.actions.change": "change", "widget.event_edit.actions.remove": "delete", + "widget.sources.create": "create", "page.login.title": "Login", "page.login.internal.name": "name", "page.login.internal.password": "password", diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index 94bbb20..7a6aa6c 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -57,13 +57,15 @@ namespace _dali.pages.overview await widget_mode_switcher.load(target_element.querySelector("#overview-mode")); } + let widget_sources : _dali.widgets.sources.class_widget_sources; let widget_weekview : _dali.widgets.weekview.class_widget_weekview; let widget_listview : _dali.widgets.listview.class_widget_listview; /** * @todo update sources */ - const update = () => { - widget_weekview.update_entries(); + const update = async () => { + await widget_weekview.update_entries(); + await widget_sources.update(); }; // hint { @@ -78,17 +80,8 @@ namespace _dali.pages.overview } // sources { - const data : Array< - { - id : _dali.type.calendar_id; - name : string; - hue : float; - access_level : _dali.type.enum_access_level; - } - > = await _dali.backend.calendar_list( - ); - const widget_sources = new _dali.widgets.sources.class_widget_sources( - data, + widget_sources = new _dali.widgets.sources.class_widget_sources( + _dali.backend.calendar_list, { "action_open": (entry) => { let read_only : boolean; @@ -161,6 +154,9 @@ namespace _dali.pages.overview widget_weekview.toggle_visibility(entry.id); widget_listview.toggle_visibility(entry.id); }, + "action_create": () => { + console.warn("not implemented: calendar_add widget"); + }, } ); await widget_sources.load(target_element.querySelector("#overview-pane-left")); diff --git a/source/style/main.css b/source/style/main.css index ea384f0..2f85e01 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -89,12 +89,14 @@ nav a:hover a { text-decoration: none; - color: hsl(var(--hue), 50%, 50%); + color: hsl(var(--hue), 0%, 87.5%); } a:hover { - color: hsl(var(--hue), 50%, 75%); + color: hsl(var(--hue), 0%, 100%); + border-bottom: 2px solid hsl(0, 0%, 100%); + transition: 1s ease color; } input,select,textarea diff --git a/source/style/widget-sources.css b/source/style/widget-sources.css index bfcb618..efc6e46 100644 --- a/source/style/widget-sources.css +++ b/source/style/widget-sources.css @@ -1,9 +1,13 @@ .sources +{ + font-size: 0.75em; +} + +.sources-entries { margin: 0; padding: 0; list-style-type: none; - font-size: 0.75em; } .sources-entry diff --git a/source/widgets/sources/logic.ts b/source/widgets/sources/logic.ts index 01c082c..53a4931 100644 --- a/source/widgets/sources/logic.ts +++ b/source/widgets/sources/logic.ts @@ -17,53 +17,230 @@ namespace _dali.widgets.sources { /** + * [dependency] */ - private keys : Array; - - - /** - */ - private data : Record; + private get_entries : (() => Promise>); /** + * [hook] */ private action_open : ((entry : type_entry) => void); /** + * [hook] */ private action_toggle_visibility : ((entry : type_entry) => void); + /** + * [hook] + */ + private action_create : (() => void); + + + /** + * [state] + */ + private container : (null | Element); + + /** */ public constructor( - entries : Array, - options : { + get_entries : (() => Promise>), + { + "action_open": action_open = ((calendar_id) => {}), + "action_toggle_visibility": action_toggle_visibility = ((calendar_id) => {}), + "action_create": action_create = (() => {}), + } + : + { action_open ?: ((entry : type_entry) => void); action_toggle_visibility ?: ((entry : type_entry) => void); - } = {} + action_create ?: (() => void); + } + = + { + } ) { - options = Object.assign( - { - "action_open": (calendar_id) => {}, - "action_toggle_visibility": (calendar_id) => {}, - }, - options + // dependencies + this.get_entries = get_entries; + + // hooks + this.action_open = action_open; + this.action_toggle_visibility = action_toggle_visibility; + this.action_create = action_create; + + // state + this.container = null; + } + + + /** + */ + private static id_encode( + id : _dali.type.calendar_id + ) + : string + { + return id.toFixed(0); + } + + + /** + */ + private static id_decode( + representation : string + ) + : _dali.type.calendar_id + { + return parseInt(representation); + } + + + /** + */ + public async update( + ) + : Promise + { + const data : lib_plankton.map.type_map<_dali.type.calendar_id, type_entry> = lib_plankton.map.hashmap.implementation_map( + lib_plankton.map.hashmap.make( + calendar_id => class_widget_sources.id_encode(calendar_id), + { + "pairs": ( + (await this.get_entries()) + .map( + entry => ({ + "key": entry.id, + "value": entry, + }) + ) + ), + } + ) ); - this.keys = []; - this.data = {}; - entries.forEach( - (entry) => { - const key : string = entry.id.toFixed(0); - this.keys.push(key); - this.data[key] = entry; - } - ); - this.action_open = options.action_open; - this.action_toggle_visibility = options.action_toggle_visibility; + // structure + { + this.container.innerHTML = await _dali.helpers.template_coin( + "widget-sources", + "main", + { + "label_create": lib_plankton.translate.get("widget.sources.create"), + "entries": ( + ( + await _dali.helpers.promise_row( + lib_plankton.map.dump(data) + .map( + (pair) => () => { + return _dali.helpers.template_coin( + "widget-sources", + "entry", + { + "name": pair.value.name, + "label_toggle": lib_plankton.string.coin( + "{{show}}/{{hide}}", + { + "show": lib_plankton.translate.get("common.show"), + "hide": lib_plankton.translate.get("common.hide"), + } + ), + "label_edit": lib_plankton.translate.get("common.edit"), + // "access_level": entry.access_level, // TODO + // TODO centralize + "color_head": lib_plankton.color.output_hex( + lib_plankton.color.make_hsv( + { + "hue": pair.value.hue, + /** + * @todo const and outsource + */ + "saturation": 0.375, + /** + * @todo const and outsource + */ + "value": 0.375, + } + ), + ), + "color_body": lib_plankton.color.output_hex( + lib_plankton.color.make_hsv( + { + "hue": pair.value.hue, + /** + * @todo const and outsource + */ + "saturation": 0.375, + /** + * @todo const and outsource + */ + "value": 0.25, + } + ), + ), + "rel": class_widget_sources.id_encode(pair.key), + } + ); + } + ) + ) + ) + .join("") + ), + } + ); + } + // listeners + { + this.container.querySelector(".sources-create").addEventListener( + "click", + (event) => { + event.preventDefault(); + this.action_create(); + } + ); + this.container.querySelectorAll(".sources-entry-head").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + element.parentElement.classList.toggle("sources-entry-open"); + } + ); + } + ); + this.container.querySelectorAll(".sources-entry-toggle").forEach( + (element) => { + element.addEventListener( + "click", + () => { + const key_encoded : string = element.parentElement.parentElement.parentElement.getAttribute("rel"); + const calendar_id : _dali.type.calendar_id = class_widget_sources.id_decode(key_encoded); + const entry : type_entry = data.get(calendar_id); + element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-hidden"); + element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-open", false); + this.action_toggle_visibility(entry); + } + ); + } + ); + this.container.querySelectorAll(".sources-entry-edit").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + const key_encoded : string = element.parentElement.parentElement.parentElement.getAttribute("rel"); + const calendar_id : _dali.type.calendar_id = class_widget_sources.id_decode(key_encoded); + const entry : type_entry = data.get(calendar_id); + this.action_open(entry); + } + ); + } + ); + } } @@ -72,100 +249,11 @@ namespace _dali.widgets.sources */ public async load( target_element : Element - ) : Promise + ) + : Promise { - target_element.innerHTML = await _dali.helpers.template_coin( - "widget-sources", - "main", - { - "entries": ( - ( - await _dali.helpers.promise_row( - this.keys - .map( - (key) => () => { - const entry : type_entry = this.data[key]; - return _dali.helpers.template_coin( - "widget-sources", - "entry", - { - "name": entry.name, - "label_toggle": lib_plankton.string.coin( - "{{show}}/{{hide}}", - { - "show": lib_plankton.translate.get("common.show"), - "hide": lib_plankton.translate.get("common.hide"), - } - ), - "label_edit": lib_plankton.translate.get("common.edit"), - // "access_level": entry.access_level, // TODO - // TODO centralize - "color_head": lib_plankton.color.output_hex( - lib_plankton.color.make_hsv( - { - "hue": entry.hue, - "saturation": 0.375, - "value": 0.375, - } - ), - ), - "color_body": lib_plankton.color.output_hex( - lib_plankton.color.make_hsv( - { - "hue": entry.hue, - "saturation": 0.375, - "value": 0.25, - } - ), - ), - "rel": key, - } - ); - } - ) - ) - ) - .join("") - ), - } - ); - target_element.querySelectorAll(".sources-entry-head").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - element.parentElement.classList.toggle("sources-entry-open"); - } - ); - } - ); - target_element.querySelectorAll(".sources-entry-toggle").forEach( - (element) => { - element.addEventListener( - "click", - () => { - const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel"); - const entry : type_entry = this.data[key]; - element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-hidden"); - element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-open", false); - this.action_toggle_visibility(entry); - } - ); - } - ); - target_element.querySelectorAll(".sources-entry-edit").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel"); - const entry : type_entry = this.data[key]; - this.action_open(entry); - } - ); - } - ); - return Promise.resolve(undefined); + this.container = target_element; + await this.update(); } } diff --git a/source/widgets/sources/templates/main.html.tpl b/source/widgets/sources/templates/main.html.tpl index 3f9a9a7..ba432fd 100644 --- a/source/widgets/sources/templates/main.html.tpl +++ b/source/widgets/sources/templates/main.html.tpl @@ -1,3 +1,6 @@ -
    - {{entries}} -
+
+
    + {{entries}} +
+ {{label_create}} +