From 25291b373adfd0c55553df2281fb01a0e1013ef7 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Mon, 20 Oct 2025 13:16:00 +0200 Subject: [PATCH] [mod] zahlreiche Anpassungen und Verbesserungen --- source/data/localization/deu.loc.json | 2 + source/data/localization/eng.loc.json | 8 +- source/helpers.ts | 20 + source/index.html.tpl | 10 +- source/pages/caldav/style.css | 22 + source/pages/overview/logic.ts | 725 ++++++++++-------- source/pages/overview/style.css | 46 ++ source/style/hacks.css | 7 +- source/style/main.css | 9 +- source/widgets/listview/logic.ts | 182 ++--- source/widgets/listview/style.css | 60 ++ source/widgets/menu/style.css | 74 ++ source/widgets/sources/logic.ts | 86 +-- source/widgets/sources/style.css | 36 + .../widgets/sources/templates/entry.html.tpl | 13 +- source/widgets/weekview/logic.ts | 544 ++++++++----- source/widgets/weekview/style.css | 131 ++++ .../widgets/weekview/templates/main.html.tpl | 52 +- tools/build | 10 +- tools/make-index | 14 - tools/makefile | 57 +- 21 files changed, 1338 insertions(+), 770 deletions(-) create mode 100644 source/pages/caldav/style.css create mode 100644 source/pages/overview/style.css create mode 100644 source/widgets/listview/style.css create mode 100644 source/widgets/menu/style.css create mode 100644 source/widgets/sources/style.css create mode 100644 source/widgets/weekview/style.css diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index a19e24e..cf92d58 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -21,6 +21,7 @@ "common.cancel": "abbrechen", "common.login": "anmelden", "common.logout": "abmelden", + "common.confirm_deletion": "sicher?", "access_level.none": "nichts", "access_level.view": "nur lesen", "access_level.edit": "lesen und bearbeiten", @@ -51,6 +52,7 @@ "widget.weekview.controls.year": "Jahr", "widget.weekview.controls.week": "Woche", "widget.weekview.controls.count": "Anzahl", + "widget.weekview.controls.vertical": "senkrecht", "widget.weekview.controls.apply": "Laden", "widget.calendar_edit.actions.add": "Kalender anlegen", "widget.calendar_edit.actions.change": "ändern", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 2e14e24..beec643 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -21,6 +21,7 @@ "common.cancel": "cancel", "common.login": "login", "common.logout": "logout", + "common.confirm_deletion": "sure?", "access_level.none": "none", "access_level.view": "read only", "access_level.edit": "read and write", @@ -48,9 +49,10 @@ "calendar.access.default_level": "default", "calendar.access.attributed": "attributed", "widget.listview.add": "add event", - "widget.weekview.controls.year": "Year", - "widget.weekview.controls.week": "Week", - "widget.weekview.controls.count": "Count", + "widget.weekview.controls.year": "year", + "widget.weekview.controls.week": "week", + "widget.weekview.controls.count": "count", + "widget.weekview.controls.vertical": "vertical", "widget.weekview.controls.apply": "Load", "widget.calendar_edit.actions.add": "add calendar", "widget.calendar_edit.actions.change": "change", diff --git a/source/helpers.ts b/source/helpers.ts index 47dfee4..92a791a 100644 --- a/source/helpers.ts +++ b/source/helpers.ts @@ -209,4 +209,24 @@ namespace _dali.helpers ); } + + /** + */ + export function event_color( + hue : float + ) + : + string + { + return lib_plankton.color.output_hex( + lib_plankton.color.make_hsv( + { + "hue": hue, + "saturation": 0.375, + "value": 0.375, + } + ), + ); + } + } diff --git a/source/index.html.tpl b/source/index.html.tpl index c2374e0..8a49cfa 100644 --- a/source/index.html.tpl +++ b/source/index.html.tpl @@ -20,15 +20,13 @@ document.addEventListener( ) } ); - -{{templates}} -
-
-
-
+
+
+
+
diff --git a/source/pages/caldav/style.css b/source/pages/caldav/style.css new file mode 100644 index 0000000..47e293b --- /dev/null +++ b/source/pages/caldav/style.css @@ -0,0 +1,22 @@ +.caldav-conf-section +{ + margin-bottom: 16px; +} + +.caldav-conf-section-label +{ + margin-left: 16px; + display: block; + font-weight: bold; + text-transform: capitalize; +} + +.caldav-conf-section-value +{ + margin-left: 32px; +} + +.caldav-conf-section-value-regular +{ + font-family: monospace; +} diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index e10ecd0..f376976 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -9,14 +9,6 @@ namespace _dali.pages.overview // params const view_mode : _dali.enum_view_mode = _dali.helpers.view_mode_determine(parameters["mode"] ?? "auto"); - /** - * @todo ordentlich machen (nicht nur week und list) - */ - const set_view_mode = (view_mode) => { - const compact : boolean = (view_mode !== _dali.enum_view_mode.week); - target_element.querySelector("#overview").classList.toggle("overview-compact", compact); - }; - // exec target_element.innerHTML = await _dali.helpers.template_coin( "overview", @@ -25,9 +17,366 @@ namespace _dali.pages.overview } ); + let widget_mode_switcher : lib_plankton.zoo_widget.interface_widget; + 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 ordentlich machen (nicht nur week und list) + */ + function set_view_mode + ( + view_mode : _dali.enum_view_mode + ) + : void + { + const compact : boolean = (view_mode !== _dali.enum_view_mode.week); + target_element.querySelector("#overview").classList.toggle("overview-compact", compact); + } + + /** + * @todo add return type + */ + async function get_available_calendars( + ) + { + return ( + (await _dali.model.calendar_list()) + .filter( + (entry) => ( + (entry.access_level === _dali.enum_access_level.edit) + || + (entry.access_level === _dali.enum_access_level.admin) + ) + ) + ); + } + + /** + * @todo add return type + */ + async function get_entries( + from_pit : lib_plankton.pit.type_pit, + to_pit : lib_plankton.pit.type_pit, + calendar_ids : Array<_dali.type_calendar_id> + ) + : Promise> + { + /** + * @todo do NOT wait? + */ + await _dali.model.sync_events( + { + "from": from_pit, + "to": to_pit, + }, + { + "calendar_ids": calendar_ids, + } + ); + /** + * @todo filter + */ + return _dali.model.event_list(); + } + + /** + * @todo update listview + */ + async function update_sources_and_entries( + { + "priviliged": priviliged = null, + } + : + { + priviliged ?: (null | boolean); + } + = + { + } + ) + : Promise + { + await widget_sources.update({"priviliged": priviliged}); + await widget_weekview.update_entries(); + } + + /** + * @todo use priviliged? + * @todo update listview + */ + async function update_entries( + { + "priviliged": priviliged = null, + } + : + { + priviliged ?: (null | boolean); + } + = + { + } + ) + : Promise + { + await widget_weekview.update_entries(); + } + + /** + */ + async function action_create_calendar( + ) + : Promise + { + const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( + await _dali.model.user_list(), + { + "read_only": false, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_add": (calendar_object) => { + _dali.model.calendar_add( + calendar_object + ) + .then( + () => { + update_sources_and_entries(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.calendar_add_error", + {"reason": String(reason)} + ); + } + ); + }, + "initial_value": null, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + } + + /** + * @todo unterschiedliches Verhalten bei Anmeldung? + */ + async function action_create_event( + { + "date": date = lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date, + } + : + { + date ?: lib_plankton.pit.type_date; + } + = + { + } + ) + : Promise + { + const widget = new _dali.widgets.event_edit.class_widget_event_edit( + (await get_available_calendars()), + { + "calendar_id": null, + "event_name": "", + "event_begin": lib_plankton.call.convey( + date, + [ + x => ({ + "timezone_shift": 0, + "date": date, + "time": {"hour": 12, "minute": 0, "second": 0} + }), + lib_plankton.pit.from_datetime, + x => lib_plankton.pit.shift_hour(x, 0), + lib_plankton.pit.to_datetime, + ] + ), + "event_end": lib_plankton.call.convey( + date, + [ + x => ({ + "timezone_shift": 0, + "date": date, + "time": {"hour": 12, "minute": 0, "second": 0} + }), + lib_plankton.pit.from_datetime, + x => lib_plankton.pit.shift_hour(x, +1), + lib_plankton.pit.to_datetime, + ] + ), + "event_location": null, + "event_link": null, + "event_description": null, + }, + { + "read_only": false, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_add": (data) => { + _dali.model.event_add( + data.calendar_id, + { + "name": data.event_name, + "begin": data.event_begin, + "end": data.event_end, + "location": data.event_location, + "link": data.event_link, + "description": data.event_description, + } + ) + .then( + () => { + update_entries(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + // todo + } + ); + }, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + } + + /** + */ + async function action_select_event + ( + event_key : _dali.type_event_key + ) + : Promise + { + const event_object_extended : _dali.type_event_object_extended = await _dali.model.event_get(event_key); + const calendar_id = event_object_extended.calendar_id; + const access_level = event_object_extended.access_level; + const event_id = event_object_extended.event_id; + /* + if (! _dali.is_logged_in()) + { + // do nothing + } + else + { + } + */ + let read_only : boolean; + switch (access_level) + { + case _dali.enum_access_level.none: + { + throw (new Error("this event should not be visible")); + break; + } + case _dali.enum_access_level.view: + { + read_only = true; + break; + } + case _dali.enum_access_level.edit: + case _dali.enum_access_level.admin: + { + read_only = false; + break; + } + } + (async () => { + const event_object : _dali.type_event_object = await _dali.backend.calendar_event_get( + calendar_id, + event_id + ); + const widget = new _dali.widgets.event_edit.class_widget_event_edit( + (await get_available_calendars()), + { + "calendar_id": calendar_id, + "event_name": event_object.name, + "event_begin": event_object.begin, + "event_end": event_object.end, + "event_location": event_object.location, + "event_link": event_object.link, + "event_description": event_object.description, + }, + { + "read_only": read_only, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_change": (data) => { + _dali.model.event_change( + event_key, + { + "name": data.event_name, + "begin": data.event_begin, + "end": data.event_end, + "location": data.event_location, + "link": data.event_link, + "description": data.event_description, + } + ) + .then( + () => { + update_entries(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.event_change.error", + {"reason": String(reason)} + ); + } + ); + }, + "action_remove": () => { + _dali.model.event_remove( + event_key + ) + .then( + () => { + update_entries(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.event_remove_error", + {"reason": String(reason)} + ); + } + ); + }, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); + } + + // hint + { + const dom_hint = target_element.querySelector("#overview-hint"); + dom_hint.textContent = lib_plankton.translate.get("page.overview.login_hint"); + dom_hint.classList.toggle("overview-hint-hidden", _dali.is_logged_in()); + } + // mode switcher { - const widget_mode_switcher : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher( + widget_mode_switcher = new _dali.widgets.mode_switcher.class_widget_mode_switcher( [ { "mode": _dali.enum_view_mode.week, @@ -57,83 +406,13 @@ 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; - - const get_available_calendars = async () => { - return ( - (await _dali.model.calendar_list()) - .filter( - (entry) => ( - (entry.access_level === _dali.enum_access_level.edit) - || - (entry.access_level === _dali.enum_access_level.admin) - ) - ) - ); - } - /** - * @todo update listview - */ - const update_sources_and_entries = async (priviliged = null) => { - await widget_sources.update({"priviliged": priviliged}); - await widget_weekview.update_entries(); - }; - /** - * @todo update listview - */ - const update_entries = async (priviliged = null) => { - await widget_weekview.update_entries(); - }; - // hint - { - const dom_hint = target_element.querySelector("#overview-hint"); - dom_hint.textContent = lib_plankton.translate.get("page.overview.login_hint"); - dom_hint.classList.toggle("overview-hint-hidden", _dali.is_logged_in()); - } // sources { widget_sources = new _dali.widgets.sources.class_widget_sources( _dali.model.calendar_list, { "initial_priviliged": _dali.is_logged_in(), - "action_create": () => { - (async () => { - const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( - await _dali.model.user_list(), - { - "read_only": false, - "action_cancel": () => { - _dali.overlay.toggle({"mode": false}); - }, - "action_add": (calendar_object) => { - _dali.model.calendar_add( - calendar_object - ) - .then( - () => { - update_sources_and_entries(); - _dali.overlay.toggle({"mode": false}); - } - ) - .catch( - (reason) => { - lib_plankton.log.warning( - "dali.overview.calendar_add_error", - {"reason": String(reason)} - ); - } - ); - }, - "initial_value": null, - } - ); - _dali.overlay.clear(); - _dali.overlay.toggle({"mode": true}); - await widget.load(_dali.overlay.get_content_element()); - }) (); - }, + "action_create": action_create_calendar, "action_open": (entry) => { let read_only : boolean; switch (entry.access_level) @@ -198,268 +477,50 @@ namespace _dali.pages.overview await widget.load(_dali.overlay.get_content_element()); }) (); }, - "action_toggle_visibility": (entry) => { - widget_weekview.toggle_visibility(entry.id); - widget_listview.toggle_visibility(entry.id); + "action_toggle_visibility": (entry, mode) => { + widget_weekview.toggle_visibility(entry.id, {"mode": mode}); + widget_listview.toggle_visibility(entry.id, {"mode": mode}); }, } ); await widget_sources.load(target_element.querySelector("#overview-pane-left")); } - // events + + // weekview { - const get_entries = async (from_pit, to_pit, calendar_ids) => { - /** - * @todo do NOT wait? - */ - await _dali.model.sync_events( + widget_weekview = ( + new _dali.widgets.weekview.class_widget_weekview( + get_entries, { - "from": from_pit, - "to": to_pit, - }, - { - "calendar_ids": calendar_ids, + "action_select_event": (event_key) => action_select_event(event_key), + "action_select_day": (date) => action_create_event({"date": date}), } - ); - /** - * @todo filter - */ - return _dali.model.event_list(); - }; - const action_select_event = async (event_key) => { - const event_object_extended : _dali.type_event_object_extended = await _dali.model.event_get(event_key); - const calendar_id = event_object_extended.calendar_id; - const access_level = event_object_extended.access_level; - const event_id = event_object_extended.event_id; - /* - if (! _dali.is_logged_in()) - { - // do nothing - } - else - { - } - */ - let read_only : boolean; - switch (access_level) - { - case _dali.enum_access_level.none: - { - throw (new Error("this event should not be visible")); - break; - } - case _dali.enum_access_level.view: - { - read_only = true; - break; - } - case _dali.enum_access_level.edit: - case _dali.enum_access_level.admin: - { - read_only = false; - break; - } - } - (async () => { - const event_object : _dali.type_event_object = await _dali.backend.calendar_event_get( - calendar_id, - event_id - ); - const widget = new _dali.widgets.event_edit.class_widget_event_edit( - (await get_available_calendars()), - { - "calendar_id": calendar_id, - "event_name": event_object.name, - "event_begin": event_object.begin, - "event_end": event_object.end, - "event_location": event_object.location, - "event_link": event_object.link, - "event_description": event_object.description, - }, - { - "read_only": read_only, - "action_cancel": () => { - _dali.overlay.toggle({"mode": false}); - }, - "action_change": (data) => { - _dali.model.event_change( - event_key, - { - "name": data.event_name, - "begin": data.event_begin, - "end": data.event_end, - "location": data.event_location, - "link": data.event_link, - "description": data.event_description, - } - ) - .then( - () => { - update_entries(); - _dali.overlay.toggle({"mode": false}); - } - ) - .catch( - (reason) => { - lib_plankton.log.warning( - "dali.overview.event_change.error", - {"reason": String(reason)} - ); - } - ); - }, - "action_remove": () => { - _dali.model.event_remove( - event_key - ) - .then( - () => { - update_entries(); - _dali.overlay.toggle({"mode": false}); - } - ) - .catch( - (reason) => { - lib_plankton.log.warning( - "dali.overview.event_remove_error", - {"reason": String(reason)} - ); - } - ); - }, - } - ); - _dali.overlay.clear(); - _dali.overlay.toggle({"mode": true}); - await widget.load(_dali.overlay.get_content_element()); - }) (); - }; - // listview - { - widget_listview = ( - new _dali.widgets.listview.class_widget_listview( - get_entries, - { - "action_select_event": action_select_event, - "action_add": () => { - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { - "calendar_id": null, - "year": null, - "month": null, - "day": null, - } - } - ); - }, - } - ) - ); - await widget_listview.load(target_element.querySelector("#overview-pane-right-listview")); - } - // weekview - { - widget_weekview = ( - new _dali.widgets.weekview.class_widget_weekview( - get_entries, - { - "action_select_event": action_select_event, - "action_select_day": (date) => { - /* - if (! _dali.is_logged_in()) - { - // do nothing - } - else - { - } - */ - (async () => { - const widget = new _dali.widgets.event_edit.class_widget_event_edit( - (await get_available_calendars()), - { - "calendar_id": null, - "event_name": "", - "event_begin": lib_plankton.call.convey( - date, - [ - x => ({ - "timezone_shift": 0, - "date": date, - "time": {"hour": 12, "minute": 0, "second": 0} - }), - lib_plankton.pit.from_datetime, - x => lib_plankton.pit.shift_hour(x, 0), - lib_plankton.pit.to_datetime, - ] - ), - "event_end": lib_plankton.call.convey( - date, - [ - x => ({ - "timezone_shift": 0, - "date": date, - "time": {"hour": 12, "minute": 0, "second": 0} - }), - lib_plankton.pit.from_datetime, - x => lib_plankton.pit.shift_hour(x, +1), - lib_plankton.pit.to_datetime, - ] - ), - "event_location": null, - "event_link": null, - "event_description": null, - }, - { - "read_only": false, - "action_cancel": () => { - _dali.overlay.toggle({"mode": false}); - }, - "action_add": (data) => { - _dali.model.event_add( - data.calendar_id, - { - "name": data.event_name, - "begin": data.event_begin, - "end": data.event_end, - "location": data.event_location, - "link": data.event_link, - "description": data.event_description, - } - ) - .then( - () => { - update_entries(); - _dali.overlay.toggle({"mode": false}); - } - ) - .catch( - (reason) => { - // todo - } - ); - }, - } - ); - _dali.overlay.clear(); - _dali.overlay.toggle({"mode": true}); - await widget.load(_dali.overlay.get_content_element()); - }) (); - }, - } - ) - ); - await widget_weekview.load(target_element.querySelector("#overview-pane-right-weekview")); - } - _dali.model.listen_reset( - async (priviliged) => { - update_sources_and_entries(priviliged); - target_element.querySelector("#overview-hint").classList.toggle("overview-hint-hidden", priviliged); - } + ) ); + await widget_weekview.load(target_element.querySelector("#overview-pane-right-weekview")); } + + // listview + { + widget_listview = ( + new _dali.widgets.listview.class_widget_listview( + get_entries, + { + "action_select": (event_key) => action_select_event(event_key), + "action_add": () => action_create_event(), + } + ) + ); + await widget_listview.load(target_element.querySelector("#overview-pane-right-listview")); + } + + _dali.model.listen_reset( + async (priviliged) => { + update_sources_and_entries({"priviliged": priviliged}); + target_element.querySelector("#overview-hint").classList.toggle("overview-hint-hidden", priviliged); + } + ); + return Promise.resolve(undefined); }, ); diff --git a/source/pages/overview/style.css b/source/pages/overview/style.css new file mode 100644 index 0000000..f60b623 --- /dev/null +++ b/source/pages/overview/style.css @@ -0,0 +1,46 @@ +#overview-head +{ + padding-bottom: 12px; + margin-bottom: 12px; + border-bottom: 1px solid; +} + +#overview-hint +{ + text-align: center; + font-weight: bold; +} + +#overview-hint.overview-hint-hidden +{ + display: none; +} + +#overview-body +{ + display: flex; + flex-direction: row; + flex-wrap: nowrap; +} + +#overview-body #overview-pane-left +{ + flex-grow: 0; + flex-shrink: 1; +} + +#overview-body #overview-pane-right +{ + flex-grow: 1; + flex-shrink: 1; +} + +#overview.overview-compact #overview-pane-left {/*flex-basis: 25%;*/display: none;} +#overview.overview-compact #overview-pane-right {flex-basis: 75%;} +#overview.overview-compact #overview-pane-right-listview {} +#overview.overview-compact #overview-pane-right-weekview {display: none;} + +#overview:not(.overview-compact) #overview-pane-left {flex-basis: 12.5%;} +#overview:not(.overview-compact) #overview-pane-right {flex-basis: 87.5%;} +#overview:not(.overview-compact) #overview-pane-right-listview {display: none;} +#overview:not(.overview-compact) #overview-pane-right-weekview {} diff --git a/source/style/hacks.css b/source/style/hacks.css index de17306..bf601e0 100644 --- a/source/style/hacks.css +++ b/source/style/hacks.css @@ -1,4 +1,9 @@ -.plankton_input_group_field[rel="resource_kind"] +.plankton_input_group_field[rel="resource"] { display: none; } + +.weekview-control-count +{ + display: none !important; +} diff --git a/source/style/main.css b/source/style/main.css index 49bbfc4..6feb245 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -99,11 +99,6 @@ a:hover transition: 1s ease color; } -input,select,textarea -{ - padding: 4px; -} - button { padding: 8px; @@ -122,6 +117,10 @@ input,select,textarea background-color: hsl(0, 0%, 25%); border: 1px solid hsl(0, 0%, 25%); color: hsl(0, 0%, 100%); + padding: 4px; margin: 4px; border-radius: 4px; + /* + font-family: monospace; + */ } diff --git a/source/widgets/listview/logic.ts b/source/widgets/listview/logic.ts index 47db5ce..9701154 100644 --- a/source/widgets/listview/logic.ts +++ b/source/widgets/listview/logic.ts @@ -1,18 +1,6 @@ namespace _dali.widgets.listview { - /** - */ - type type_entry = { - calendar_id : _dali.type_calendar_id; - calendar_name : string; - hue : float; - access_level : _dali.enum_access_level; - event_id : (null | _dali.type_local_resource_event_id); - event_object : _dali.type_event_object; - }; - - /** */ type type_get_entries = ( @@ -22,7 +10,7 @@ namespace _dali.widgets.listview calendar_ids : Array<_dali.type_calendar_id> ) => - Promise> + Promise> ); @@ -32,22 +20,17 @@ namespace _dali.widgets.listview { /** + * [dependency] */ private get_entries : type_get_entries; /** + * [hook] */ - private container : (null | Element); - - - /** - */ - private action_select_event : ( + private action_select : ( ( - calendar_id : _dali.type_calendar_id, - access_level : _dali.enum_access_level, - event_id : _dali.type_local_resource_event_id + event_key : _dali.type_event_key ) => void @@ -55,6 +38,7 @@ namespace _dali.widgets.listview /** + * [hook] */ private action_add : ( ( @@ -64,16 +48,32 @@ namespace _dali.widgets.listview ); + /** + */ + private include_passed : boolean; + + + /** + * [state] + */ + private container : (null | Element); + + /** */ public constructor( get_entries : type_get_entries, - options : { - action_select_event ?: ( + { + "include_passed": include_passed = false, + "action_select": action_select = ((event_key) => {}), + "action_add": action_add = (() => {}), + } + : + { + include_passed ?: boolean; + action_select ?: ( ( - calendar_id : _dali.type_calendar_id, - access_level : _dali.enum_access_level, - event_id : _dali.type_local_resource_event_id + event_key : _dali.type_event_key ) => void @@ -84,39 +84,57 @@ namespace _dali.widgets.listview => void ); - } = {} + } + = + { + } ) { - options = Object.assign( - { - "action_select_event": (calendar_id, access_level, event_id) => {}, - "action_select_add": () => {}, - }, - options - ); + // dependencies this.get_entries = get_entries; + + // hooks + this.action_select = action_select; + this.action_add = action_add; + + // state + this.include_passed = include_passed; this.container = null; - this.action_select_event = options.action_select_event; - this.action_add = options.action_add; } /** */ public toggle_visibility( - calendar_id : _dali.type_calendar_id - ) : void + calendar_id : _dali.type_calendar_id, + { + "mode": mode = null, + } + : + { + mode ?: (null | boolean); + } + = + { + } + ) + : void { this.container.querySelectorAll(".listview-entry").forEach( (element) => { const rel : string = element.getAttribute("rel"); const parts : Array = rel.split("/"); const calendar_id_ : _dali.type_calendar_id = parseInt(parts[0]); - if (! (calendar_id === calendar_id_)) { + if (! (calendar_id === calendar_id_)) + { // do nothing } - else { - element.classList.toggle("listview-entry-hidden"); + else + { + element.classList.toggle( + "listview-entry-hidden", + ((mode !== null) ? (! mode) : undefined) + ); } } ); @@ -128,12 +146,13 @@ namespace _dali.widgets.listview */ public async load( target_element : Element - ) : Promise + ) + : Promise { const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); const from_pit : lib_plankton.pit.type_pit = now_pit; const to_pit : lib_plankton.pit.type_pit = lib_plankton.pit.shift_week(now_pit, +4); - const entries : Array = await this.get_entries( + const entries : Array<_dali.type_event_object_extended> = await this.get_entries( from_pit, to_pit, null @@ -165,6 +184,18 @@ namespace _dali.widgets.listview ( await _dali.helpers.promise_row( entries + .filter( + (entry) => ( + this.include_passed + ? + true + : + lib_plankton.pit.is_after( + lib_plankton.pit.from_datetime(entry.event_object.begin), + now_pit + ) + ) + ) .map( (entry) => () => _dali.helpers.template_coin( "widget-listview", @@ -228,36 +259,8 @@ namespace _dali.widgets.listview entry.event_object.description ), "raw": JSON.stringify(entry), - "color": lib_plankton.color.output_hex( - lib_plankton.color.make_hsv( - { - "hue": entry.hue, - "saturation": 0.375, - "value": 0.375, - } - ), - ), - "rel": lib_plankton.string.coin( - "{{calendar_id}}/{{event_id}}/{{access_level}}", - { - "calendar_id": entry.calendar_id.toFixed(0), - "event_id": ( - (! (entry.event_id === null)) - ? - entry.event_id.toFixed(0) - : - "-" - ), - "access_level": (() => { - switch (entry.access_level) { - case _dali.enum_access_level.none: return "none"; - case _dali.enum_access_level.view: return "view"; - case _dali.enum_access_level.edit: return "edit"; - case _dali.enum_access_level.admin: return "admin"; - } - }) (), - } - ), + "color": _dali.helpers.event_color(entry.hue), + "rel": entry.key, }, ) ) @@ -283,33 +286,14 @@ namespace _dali.widgets.listview element.addEventListener( "click", (event) => { - if ((event.target as Element).nodeName === "A") { + if ((event.target as Element).nodeName === "A") + { // do nothing } - else { - const rel : string = element.getAttribute("rel"); - const parts : Array = rel.split("/"); - const calendar_id : _dali.type_calendar_id = parseInt(parts[0]); - const event_id : (null | _dali.type_local_resource_event_id) = ( - parts[1] === "-" - ? - null - : - parseInt(parts[1]) - ); - const access_level : _dali.enum_access_level = (() => { - switch (parts[2]) { - case "none": return _dali.enum_access_level.none; - case "view": return _dali.enum_access_level.view; - case "edit": return _dali.enum_access_level.edit; - case "admin": return _dali.enum_access_level.admin; - } - }) (); - this.action_select_event( - calendar_id, - access_level, - event_id, - ); + else + { + const event_key : string = element.getAttribute("rel"); + this.action_select(event_key); } } ); diff --git a/source/widgets/listview/style.css b/source/widgets/listview/style.css new file mode 100644 index 0000000..7943027 --- /dev/null +++ b/source/widgets/listview/style.css @@ -0,0 +1,60 @@ +.listview-add +{ + margin-left: 12px; +} + +.listview-add-hidden +{ + display: none; +} + +.listview-entries +{ + padding: 0; + margin: 0; + list-style-type: none; +} + +.listview-entry +{ + background: hsl(0,0%,25%); + padding: 12px; + border-radius: 4px; + margin: 12px; + cursor: pointer; +} + +.listview-entry-hidden +{ + display: none; +} + +.listview-entry-name +{ + font-weight: bold; + font-size: 1.25em; +} + +.listview-entry-label +{ + font-weight: bold; +} + +.listview-entry-label::before +{ + content: "["; +} + +.listview-entry-label::after +{ + content: "] "; +} + +.listview-entry-field-empty { + display: none; +} + +.listview-entry-field:not(:last-child) +{ + margin-bottom: 16px; +} diff --git a/source/widgets/menu/style.css b/source/widgets/menu/style.css new file mode 100644 index 0000000..ab45279 --- /dev/null +++ b/source/widgets/menu/style.css @@ -0,0 +1,74 @@ +.widget-menu +{ + margin-left: auto; + margin-right: 8px; + width: fit-content; +} + +.widget-menu.widget-menu-collapsed > .widget-menu-platform +{ + display: none; +} + +.widget-menu-button +{ + text-transform: initial; +} + +.widget-menu-entry +{ + cursor: pointer; +} + +.widget-menu-platform +{ + background-color: hsl(var(--hue), 0%, 25%); + + border-radius: 2px; + border: 1px solid hsl(var(--hue), 0%, 0%); + + padding: 8px; + + min-width: 200px; +} + +.widget-menu-platform:not(.widget-menu-platform-collapsed) +{ + position: fixed; + top: 50px; + right: 20px; + z-index: 2; +} + +.widget-menu-entries +{ + padding: 0; + margin: 0; + list-style-type: none; +} + +.widget-menu-entry +{ + margin: 8px; + text-transform: capitalize; +} + +.widget-menu-entry:not(:hover) +{ + background-color: hsl(var(--hue), 0%, 25%); + color: hsl(var(--hue), 0%, 100%); +} + +.widget-menu-entry:hover::before +{ + content: "» "; + /* + background-color: hsl(var(--hue), 0%, 50%); + color: hsl(var(--hue), 0%, 100%); + */ +} + +.widget-menu-entry.widget-menu-entry-hidden +{ + display: none; +} diff --git a/source/widgets/sources/logic.ts b/source/widgets/sources/logic.ts index b8cd927..f090b1d 100644 --- a/source/widgets/sources/logic.ts +++ b/source/widgets/sources/logic.ts @@ -31,7 +31,7 @@ namespace _dali.widgets.sources /** * [hook] */ - private action_toggle_visibility : ((entry : type_entry) => void); + private action_toggle_visibility : ((entry : type_entry, mode : boolean) => void); /** @@ -41,6 +41,7 @@ namespace _dali.widgets.sources /** + * [state] */ private priviliged : boolean; @@ -57,14 +58,14 @@ namespace _dali.widgets.sources get_entries : (() => Promise>), { "action_open": action_open = ((calendar_id) => {}), - "action_toggle_visibility": action_toggle_visibility = ((calendar_id) => {}), + "action_toggle_visibility": action_toggle_visibility = ((calendar_id, mode) => {}), "action_create": action_create = (() => {}), "initial_priviliged": initial_priviliged = false, } : { action_open ?: ((entry : type_entry) => void); - action_toggle_visibility ?: ((entry : type_entry) => void); + action_toggle_visibility ?: ((entry : type_entry, mode : boolean) => void); action_create ?: (() => void); initial_priviliged ?: boolean; } @@ -169,46 +170,8 @@ namespace _dali.widgets.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, - } - ), - ), + "color": _dali.helpers.event_color(pair.value.hue), "rel": class_widget_sources.id_encode(pair.key), } ); @@ -231,40 +194,37 @@ namespace _dali.widgets.sources this.action_create(); } ); - this.container.querySelectorAll(".sources-entry-head").forEach( + this.container.querySelectorAll(".sources-entry-visibility").forEach( (element) => { element.addEventListener( - "click", - (event) => { - element.parentElement.classList.toggle("sources-entry-open"); - } - ); - } - ); - this.container.querySelectorAll(".sources-entry-toggle").forEach( - (element) => { - element.addEventListener( - "click", + "change", () => { - const key_encoded : string = element.parentElement.parentElement.parentElement.getAttribute("rel"); + const mode : boolean = (element as HTMLInputElement).checked; + const key_encoded : string = element.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); + element.parentElement.classList.toggle("sources-entry-hidden", (! mode)); + this.action_toggle_visibility(entry, mode); } ); } ); - this.container.querySelectorAll(".sources-entry-edit").forEach( + this.container.querySelectorAll(".sources-entry").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); + if ((event.target as Element).classList.contains("sources-entry-visibility")) + { + // do nothing + } + else + { + const key_encoded : string = element.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); + } } ); } diff --git a/source/widgets/sources/style.css b/source/widgets/sources/style.css new file mode 100644 index 0000000..cf6201a --- /dev/null +++ b/source/widgets/sources/style.css @@ -0,0 +1,36 @@ +.sources +{ + font-size: 0.75em; +} + +.sources:not(.sources-priviliged) > .sources-create +{ + display: none; +} + +.sources-create +{ + margin-left: 8px; +} + +.sources-entries +{ + margin: 0; + padding: 0; + list-style-type: none; +} + +.sources-entry +{ + margin: 8px; + padding: 4px; + + cursor: pointer; +} + +/* +.sources-entry-hidden +{ + filter: saturate(0); +} + */ diff --git a/source/widgets/sources/templates/entry.html.tpl b/source/widgets/sources/templates/entry.html.tpl index 2ec8c57..abcd33c 100644 --- a/source/widgets/sources/templates/entry.html.tpl +++ b/source/widgets/sources/templates/entry.html.tpl @@ -1,11 +1,4 @@ -
  • -
    - {{name}} -
    -
    -
      -
    • {{label_toggle}}
    • -
    • {{label_edit}}
    • -
    -
    +
  • + + {{name}}
  • diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index 1d20719..bc2fd79 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -1,19 +1,6 @@ namespace _dali.widgets.weekview { - /** - */ - type type_entry = { - key : _dali.type_event_key; - calendar_id : _dali.type_calendar_id; - calendar_name : string; - hue : float; - access_level : _dali.enum_access_level; - event_id : (null | _dali.type_local_resource_event_id); - event_object : _dali.type_event_object; - }; - - /** */ type type_get_entries = ( @@ -23,7 +10,7 @@ namespace _dali.widgets.weekview calendar_ids : Array<_dali.type_calendar_id> ) => - Promise> + Promise> ); @@ -62,6 +49,12 @@ namespace _dali.widgets.weekview ); + /** + * [state] + */ + private vertical : boolean; + + /** * [state] */ @@ -105,9 +98,10 @@ namespace _dali.widgets.weekview { "action_select_day": action_select_day = ((date) => {}), "action_select_event": action_select_event = ((event_key) => {}), + "vertical": vertical = true, "initial_year": initial_year = null, "initial_week": initial_week = null, - "initial_count": initial_count = 5, + "initial_count": initial_count = 4, } : { @@ -125,6 +119,7 @@ namespace _dali.widgets.weekview => void ); + vertical ?: boolean; initial_year ?: (null | int); initial_week ?: (null | int); initial_count ?: int; @@ -142,6 +137,7 @@ namespace _dali.widgets.weekview // state const ywd_now : lib_plankton.pit.type_ywd = lib_plankton.pit.to_ywd(lib_plankton.pit.now()); + this.vertical = vertical; this.year = ( initial_year ?? @@ -174,7 +170,7 @@ namespace _dali.widgets.weekview * @todo sha256 hash? */ private static entry_hash( - entry : type_entry + entry : _dali.type_event_object_extended ) : string { return lib_plankton.call.convey( @@ -303,7 +299,7 @@ namespace _dali.widgets.weekview { } ) - : Promise> + : Promise> { const entries = await this.get_entries( lib_plankton.pit.from_ywd( @@ -342,7 +338,7 @@ namespace _dali.widgets.weekview /** */ private async entry_insert( - entry : type_entry + entry : _dali.type_event_object_extended ) : Promise<(null | HTMLElement)> { const selector : string = lib_plankton.string.coin( @@ -369,21 +365,7 @@ namespace _dali.widgets.weekview "widget-weekview", "tableview-cell-entry", { - "color": lib_plankton.color.output_hex( - lib_plankton.color.make_hsv( - { - "hue": entry.hue, - /** - * @todo as constant - */ - "saturation": 0.375, - /** - * @todo as constant - */ - "value": 0.375, - } - ) - ), + "color": _dali.helpers.event_color(entry.hue), "title": class_widget_weekview.event_generate_tooltip( entry.calendar_name, entry.event_object @@ -423,7 +405,7 @@ namespace _dali.widgets.weekview /** */ private async entry_add( - entry : type_entry + entry : _dali.type_event_object_extended ) : Promise { const dom_entry : (null | HTMLElement) = await this.entry_insert(entry); @@ -448,7 +430,7 @@ namespace _dali.widgets.weekview */ private async entry_update( key : _dali.type_event_key, - entry : type_entry + entry : _dali.type_event_object_extended ) : Promise { if (! this.event_map.has(key)) @@ -536,12 +518,12 @@ namespace _dali.widgets.weekview public async update_entries( ) : Promise { - const entries : Array = await this.get_entries_wrapped( + const entries : Array<_dali.type_event_object_extended> = await this.get_entries_wrapped( ); const contrast = lib_plankton.list.contrast< any, - type_entry + _dali.type_event_object_extended >( lib_plankton.map.dump(this.event_map), pair => pair.key, @@ -578,9 +560,10 @@ namespace _dali.widgets.weekview ) : Promise { const context : Element = this.container; - (context.querySelector(".weekview-control-year > input") as HTMLInputElement).value = this.year.toFixed(0); - (context.querySelector(".weekview-control-week > input") as HTMLInputElement).value = this.week.toFixed(0); - (context.querySelector(".weekview-control-count > input") as HTMLInputElement).value = this.count.toFixed(0); + (context.querySelector(".weekview-control-year input") as HTMLInputElement).value = this.year.toFixed(0); + (context.querySelector(".weekview-control-week input") as HTMLInputElement).value = this.week.toFixed(0); + (context.querySelector(".weekview-control-count input") as HTMLInputElement).value = this.count.toFixed(0); + (context.querySelector(".weekview-control-vertical input") as HTMLInputElement).checked = this.vertical; } @@ -596,6 +579,13 @@ namespace _dali.widgets.weekview const context : Element = this.container; // structure { + type type_row_data = Array< + { + week : int; + day_pits : Array; + } + >; + /** * @todo als Variable? */ @@ -603,127 +593,217 @@ namespace _dali.widgets.weekview const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); const today_begin_pit : lib_plankton.pit.type_pit = lib_plankton.pit.trunc_day(now_pit); const today_end_pit : lib_plankton.pit.type_pit = lib_plankton.pit.shift_day(today_begin_pit, 1); - const row_data : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - today : boolean; - } - >; - } - > = ( + const day_names : Array = [ + lib_plankton.translate.get("common.weekday.monday"), + lib_plankton.translate.get("common.weekday.tuesday"), + lib_plankton.translate.get("common.weekday.wednesday"), + lib_plankton.translate.get("common.weekday.thursday"), + lib_plankton.translate.get("common.weekday.friday"), + lib_plankton.translate.get("common.weekday.saturday"), + lib_plankton.translate.get("common.weekday.sunday"), + ]; + const row_data_original : type_row_data = ( lib_plankton.list.sequence(this.count) .map( offset => { const week : int = (this.week + offset); return { "week": week, - "data": ( + "day_pits": ( lib_plankton.list.sequence(7) .map( - day => { - const day_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( - { - "year": this.year, - "week": week, - "day": (day + 1), - }, - { - "timezone_shift": timezone_shift, - } - ); - return { - "pit": day_pit, - "today": lib_plankton.pit.is_between( - day_pit, - today_begin_pit, - today_end_pit - ), - }; - } + day => lib_plankton.pit.from_ywd( + { + "year": this.year, + "week": week, + "day": (1 + day), + }, + { + "timezone_shift": timezone_shift, + } + ) ) ), }; } ) ); - context.querySelector(".weekview-table tbody").innerHTML = ( - await _dali.helpers.promise_row( - row_data - .map( - (row) => async () => _dali.helpers.template_coin( - "widget-weekview", - "tableview-row", - { - "week": row.week.toFixed(0).padStart(2, "0"), - "cells": ( - await _dali.helpers.promise_row( - row.data - .map( - (cell) => async () => _dali.helpers.template_coin( - "widget-weekview", - "tableview-cell", - { - "extra_classes": ( - [""] - .concat(cell.today ? ["weekview-cell-today"] : []) - .join(" ") - ), - "title": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime_ce, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } + const row_data_alternative : type_row_data = ( + lib_plankton.list.sequence(7) + .map( + day_of_week => { + return { + /*"day_of_week"*/"week": day_of_week, + /*"week_pits"*/"day_pits": ( + lib_plankton.list.sequence(this.count) + .map( + offset => { + const week : int = (this.week + offset); + return lib_plankton.pit.from_ywd( + { + "year": this.year, + "week": week, + "day": (1 + day_of_week), + }, + { + "timezone_shift": timezone_shift, + } + ); + } + ) + ) + }; + } + ) + ); + const row_data : type_row_data = ( + (! this.vertical) + ? + row_data_original + : + row_data_alternative + ); + // head + { + const dom_tr = document.createElement("tr"); + { + if (! this.vertical) + { + // anchor + { + const dom_th = document.createElement("th"); + dom_th.classList.add("weekview-cell"); + dom_tr.appendChild(dom_th); + } + // days + { + day_names.forEach( + (day_name) => { + const dom_th = document.createElement("th"); + dom_th.classList.add("weekview-cell"); + dom_th.classList.add("weekview-cell-week"); + dom_th.textContent = day_name; + dom_tr.appendChild(dom_th); + } + ); + } + } + else + { + // anchor + { + const dom_th = document.createElement("th"); + dom_th.classList.add("weekview-cell"); + dom_tr.appendChild(dom_th); + } + // days + { + lib_plankton.list.sequence(this.count).forEach( + (offset) => { + const dom_th = document.createElement("th"); + dom_th.classList.add("weekview-cell"); + dom_th.classList.add("weekview-cell-day"); + dom_th.textContent = (this.week + offset).toFixed(0).padStart(2, "0"); + dom_tr.appendChild(dom_th); + } + ); + } + } + } + context.querySelector(".weekview-table thead").innerHTML = ""; + context.querySelector(".weekview-table thead").appendChild(dom_tr); + } + // body + { + context.querySelector(".weekview-table tbody").innerHTML = ( + await _dali.helpers.promise_row( + row_data + .map( + (row, index) => async () => _dali.helpers.template_coin( + "widget-weekview", + "tableview-row", + { + "week": ( + (! this.vertical) + ? + row.week.toFixed(0).padStart(2, "0") + : + day_names[index] + ), + "cells": ( + await _dali.helpers.promise_row( + row.day_pits + .map( + (day_pit) => async () => { + const is_today : boolean = lib_plankton.pit.is_between( + day_pit, + today_begin_pit, + today_end_pit + ); + return _dali.helpers.template_coin( + "widget-weekview", + "tableview-cell", + { + "extra_classes": ( + [""] + .concat(is_today ? ["weekview-cell-today"] : []) + .join(" ") ), - ] - ), - "day": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime_ce, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } + "title": lib_plankton.call.convey( + day_pit, + [ + lib_plankton.pit.to_datetime_ce, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ), + ] ), - ] - ), - "rel": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime_ce, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ) - ] - ), - "entries": "" + "day": lib_plankton.call.convey( + day_pit, + [ + lib_plankton.pit.to_datetime_ce, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ), + ] + ), + "rel": lib_plankton.call.convey( + day_pit, + [ + lib_plankton.pit.to_datetime_ce, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ) + ] + ), + "entries": "" + } + ); } ) ) - ) - ).join(""), - } + ).join(""), + } + ) ) ) - ) - ).join(""); + ).join(""); + } } // listeners { @@ -782,7 +862,10 @@ namespace _dali.widgets.weekview } else { - element.classList.toggle("weekview-cell-hidden", mode ?? undefined); + element.classList.toggle( + "weekview-cell-hidden", + ((mode !== null) ? (! mode) : undefined) + ); } } ); @@ -803,51 +886,164 @@ namespace _dali.widgets.weekview "label_control_year": lib_plankton.translate.get("widget.weekview.controls.year"), "label_control_week": lib_plankton.translate.get("widget.weekview.controls.week"), "label_control_count": lib_plankton.translate.get("widget.weekview.controls.count"), + "label_control_vertical": lib_plankton.translate.get("widget.weekview.controls.vertical"), "label_control_apply": lib_plankton.translate.get("widget.weekview.controls.apply"), - "label_weekday_monday": lib_plankton.translate.get("common.weekday.monday"), - "label_weekday_tuesday": lib_plankton.translate.get("common.weekday.tuesday"), - "label_weekday_wednesday": lib_plankton.translate.get("common.weekday.wednesday"), - "label_weekday_thursday": lib_plankton.translate.get("common.weekday.thursday"), - "label_weekday_friday": lib_plankton.translate.get("common.weekday.friday"), - "label_weekday_saturday": lib_plankton.translate.get("common.weekday.saturday"), - "label_weekday_sunday": lib_plankton.translate.get("common.weekday.sunday"), } ); this.container = target_element.querySelector(".weekview"); // controls { - [ + // direct inputs + { + [ + { + "name": "year", + "selector": ".weekview-control-year input", + "retrieve": element => parseInt(element.value), + "write": x => {this.year = x;} + }, + { + "name": "week", + "selector": ".weekview-control-week input", + "retrieve": element => parseInt(element.value), + "write": x => {this.week = x;} + }, + { + "name": "count", + "selector": ".weekview-control-count input", + "retrieve": element => parseInt(element.value), + "write": x => {this.count = x;} + }, + { + "name": "vertical", + "selector": ".weekview-control-vertical input", + "retrieve": element => element.checked, + "write": x => {this.vertical = x;} + }, + ].forEach( + (entry) => { + const element : HTMLInputElement = (target_element.querySelector(entry.selector) as HTMLInputElement); + element.addEventListener( + "change", + async (event) => { + event.preventDefault(); + const value : unknown = entry.retrieve(element); + entry.write(value); + await this.update_table(); + await this.update_entries(); + } + ); + } + ); + } + // buttons + { + // year { - "name": "year", - "transform": parseInt, - "write": x => {this.year = x;} - }, - { - "name": "week", - "transform": parseInt, - "write": x => {this.week = x;} - }, - { - "name": "count", - "transform": parseInt, - "write": x => {this.count = x;} - }, - ].forEach( - (entry) => { - const selector : string = (".weekview-control-" + entry.name + " > input"); - const element : HTMLInputElement = (target_element.querySelector(selector) as HTMLInputElement); - element.addEventListener( - "change", - async (event) => { - event.preventDefault(); - const value : int = entry.transform(element.value); - entry.write(value); + /** + * @todo limit + */ + target_element.querySelector(".weekview-control-year-prev").addEventListener( + "click", + async () => { + this.year -= 1; + await this.update_controls(); + await this.update_table(); + await this.update_entries(); + } + ); + /** + * @todo limit + */ + target_element.querySelector(".weekview-control-year-next").addEventListener( + "click", + async () => { + this.year += 1; + await this.update_controls(); await this.update_table(); await this.update_entries(); } ); } - ); + // week + { + target_element.querySelector(".weekview-control-week-prev").addEventListener( + "click", + async () => { + if (this.week >= 1) + { + this.week -= 1; + } + else + { + this.year -= 1; + /** + * @todo get correct week + */ + this.week = 51; + } + await this.update_controls(); + await this.update_table(); + await this.update_entries(); + } + ); + target_element.querySelector(".weekview-control-week-next").addEventListener( + "click", + async () => { + /** + * @todo correct limit + */ + if (this.week <= 51) + { + this.week += 1; + } + else + { + this.year += 1; + this.week = 1; + } + await this.update_controls(); + await this.update_table(); + await this.update_entries(); + } + ); + } + // count + { + target_element.querySelector(".weekview-control-count-prev").addEventListener( + "click", + async () => { + if (this.count >= 2) + { + this.count -= 1; + await this.update_controls(); + await this.update_table(); + await this.update_entries(); + } + else + { + // do nothing + } + } + ); + target_element.querySelector(".weekview-control-count-next").addEventListener( + "click", + async () => { + if (this.count <= 6) + { + this.count += 1; + await this.update_controls(); + await this.update_table(); + await this.update_entries(); + } + else + { + // do nothing + } + } + ); + } + } } await this.update_controls(); await this.update_table(); diff --git a/source/widgets/weekview/style.css b/source/widgets/weekview/style.css new file mode 100644 index 0000000..f9c98fd --- /dev/null +++ b/source/widgets/weekview/style.css @@ -0,0 +1,131 @@ +.weekview-controls +{ + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: right; + + margin-bottom: 12px; + + text-align: center; +} + +.weekview-control +{ + flex-basis: 0; + flex-grow: 0; + flex-shrink: 1; + + min-width: 140px; + margin: 0 12px; +} + +.weekview-control-label +{ + display: block; + + font-size: 0.75em; + /* + text-transform: uppercase; + */ +} + +.weekview-control-input > * +{ + display: inline-block; +} + +.weekview-control input +{ + max-width: 40px; +} + +.weekview-table table +{ + width: 100%; + border-collapse: collapse; +} + +.weekview-cell +{ + border: 1px solid hsl(0,0%,37.5%); + padding: 8px; + vertical-align: top; +} + +.weekview-cell-day +{ + /* todo */ + width: 13.5%; +} + +.weekview-cell-week +{ + /* todo */ + width: 5.5%; +} + +.weekview-cell-regular +{ + /* todo */ + width: 13.5%; + height: 100px; + + cursor: copy; +} + +.weekview-cell-today +{ + outline: 2px solid hsl(0, 0%, 100%); +} + +.weekview-cell-hidden +{ + display: none; +} + +.weekview-day +{ + font-size: 0.75em; + cursor: help; +} + +.weekview-events +{ + margin: 0; + padding: 0; + list-style-type: none; +} + +.weekview-event_entry +{ + margin: 4px; + padding: 4px; + border-radius: 2px; + font-size: 0.75em; + color: #FFF; + font-weight: bold; + + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + min-width: 75px; + word-wrap: anywhere; +} + +.weekview-event_entry.access_level-none +, +.weekview-event_entry.access_level-view +{ + /* + cursor: default; + */ + cursor: pointer; +} + +.weekview-event_entry.access_level-edit +, +.weekview-event_entry.access_level-admin +{ + cursor: pointer; +} diff --git a/source/widgets/weekview/templates/main.html.tpl b/source/widgets/weekview/templates/main.html.tpl index 30a6ee5..7d4be90 100644 --- a/source/widgets/weekview/templates/main.html.tpl +++ b/source/widgets/weekview/templates/main.html.tpl @@ -1,31 +1,39 @@
    - - - +
    + +
    + + + +
    +
    +
    + +
    + + + +
    +
    +
    + +
    + + + +
    +
    +
    + +
    + +
    +
    - - - - - - - - - - diff --git a/tools/build b/tools/build index 18e0282..49e1bd3 100755 --- a/tools/build +++ b/tools/build @@ -24,16 +24,24 @@ def main(): metavar = "", help = "conf path", ) + argument_parser.add_argument( + "-f", + "--force", + action = 'store_true', + default = False, + help = "force", + ) args = argument_parser.parse_args() ## exec targets = [] targets.append("default") _os.system( - "make dir_build=%s --file=tools/makefile %s" + "make dir_build=%s --file=tools/makefile %s%s" % ( args.output_directory, " ".join(targets), + (" --always-make" if args.force else ""), ) ) if True: diff --git a/tools/make-index b/tools/make-index index dc1f8d8..f2cee18 100755 --- a/tools/make-index +++ b/tools/make-index @@ -31,14 +31,6 @@ def main( dest = "index_template_path", type = str, ) - argument_parser.add_argument( - "-t", - "--template", - dest = "template_paths", - type = str, - action = "append", - default = [] - ) args = argument_parser.parse_args() ## exec @@ -46,12 +38,6 @@ def main( string_coin( file_read(args.index_template_path), { - "templates": "".join( - map( - file_read, - args.template_paths - ) - ), } ) ) diff --git a/tools/makefile b/tools/makefile index 45634f4..42319cc 100644 --- a/tools/makefile +++ b/tools/makefile @@ -26,9 +26,7 @@ ${dir_build}/index.html: \ ${dir_source}/index.html.tpl @ ${cmd_log} "index …" @ ${cmd_mkdir} $(dir $@) - @ tools/make-index \ - ${dir_source}/index.html.tpl \ - > $@ + @ tools/make-index ${dir_source}/index.html.tpl > $@ .PHONY: templates templates: \ @@ -37,80 +35,68 @@ templates: \ templates-widgets-listview \ templates-widgets-weekview \ templates-widgets-mode_switcher \ - templates-widgets-calendar_edit \ - templates-widgets-event_edit \ templates-pages-caldav \ templates-pages-overview .PHONY: templates-widgets-login templates-widgets-login: \ $(wildcard ${dir_source}/widgets/login/templates/*) - @ ${cmd_log} "templates:widgets:login …" + @ ${cmd_log} "templates:widget:login …" @ ${cmd_mkdir} ${dir_build}/templates/widget-login @ ${cmd_cp} -r -u -v ${dir_source}/widgets/login/templates/* ${dir_build}/templates/widget-login/ .PHONY: templates-widgets-sources templates-widgets-sources: \ $(wildcard ${dir_source}/widgets/sources/templates/*) - @ ${cmd_log} "templates:widgets:sources …" + @ ${cmd_log} "templates:widget:sources …" @ ${cmd_mkdir} ${dir_build}/templates/widget-sources @ ${cmd_cp} -r -u -v ${dir_source}/widgets/sources/templates/* ${dir_build}/templates/widget-sources/ .PHONY: templates-widgets-listview templates-widgets-listview: \ $(wildcard ${dir_source}/widgets/listview/templates/*) - @ ${cmd_log} "templates:widgets:listview …" + @ ${cmd_log} "templates:widget:listview …" @ ${cmd_mkdir} ${dir_build}/templates/widget-listview @ ${cmd_cp} -r -u -v ${dir_source}/widgets/listview/templates/* ${dir_build}/templates/widget-listview/ .PHONY: templates-widgets-weekview templates-widgets-weekview: \ $(wildcard ${dir_source}/widgets/weekview/templates/*) - @ ${cmd_log} "templates:widgets:weekview …" + @ ${cmd_log} "templates:widget:weekview …" @ ${cmd_mkdir} ${dir_build}/templates/widget-weekview @ ${cmd_cp} -r -u -v ${dir_source}/widgets/weekview/templates/* ${dir_build}/templates/widget-weekview/ .PHONY: templates-widgets-mode_switcher templates-widgets-mode_switcher: \ $(wildcard ${dir_source}/widgets/mode_switcher/templates/*) - @ ${cmd_log} "templates:widgets:mode_switcher …" + @ ${cmd_log} "templates:widget:mode_switcher …" @ ${cmd_mkdir} ${dir_build}/templates/widget-mode_switcher @ ${cmd_cp} -r -u -v ${dir_source}/widgets/mode_switcher/templates/* ${dir_build}/templates/widget-mode_switcher/ -.PHONY: templates-widgets-calendar_edit -templates-widgets-calendar_edit: \ - $(wildcard ${dir_source}/widgets/calendar_edit/templates/*) - @ ${cmd_log} "templates:widgets:calendar_edit …" - @ ${cmd_mkdir} ${dir_build}/templates/widget-calendar_edit - # @ ${cmd_cp} -r -u -v ${dir_source}/widgets/calendar_edit/templates/* ${dir_build}/templates/widget-calendar_edit/ - -.PHONY: templates-widgets-event_edit -templates-widgets-event_edit: \ - $(wildcard ${dir_source}/pages/event_edit/templates/*) - @ ${cmd_log} "templates:widgets:event_edit …" - @ ${cmd_mkdir} ${dir_build}/templates/widget-event_edit - # @ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/widget-uevent_edit/ - .PHONY: templates-pages-caldav templates-pages-caldav: \ $(wildcard ${dir_source}/pages/caldav/templates/*) - @ ${cmd_log} "templates:caldav …" + @ ${cmd_log} "templates:page:caldav …" @ ${cmd_mkdir} ${dir_build}/templates/caldav @ ${cmd_cp} -r -u -v ${dir_source}/pages/caldav/templates/* ${dir_build}/templates/caldav/ .PHONY: templates-pages-overview templates-pages-overview: \ $(wildcard ${dir_source}/pages/overview/templates/*) - @ ${cmd_log} "templates:overview …" + @ ${cmd_log} "templates:page:overview …" @ ${cmd_mkdir} ${dir_build}/templates/overview @ ${cmd_cp} -r -u -v ${dir_source}/pages/overview/templates/* ${dir_build}/templates/overview/ .PHONY: style -style: \ - $(wildcard ${dir_source}/style/*) +style: ${dir_build}/style.css + +${dir_build}/style.css: \ + $(wildcard ${dir_source}/style/*.css) \ + $(wildcard ${dir_source}/widgets/*/style.css) \ + $(wildcard ${dir_source}/pages/*/style.css) @ ${cmd_log} "style …" @ ${cmd_mkdir} ${dir_build} - @ ${cmd_cat} ${dir_source}/style/* > ${dir_build}/style.css + @ ${cmd_cat} $^ > $@ .PHONY: logic logic: ${dir_build}/logic.js @@ -123,18 +109,9 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/types.ts \ ${dir_source}/model.ts \ ${dir_source}/helpers.ts \ - ${dir_source}/widgets/login/logic.ts \ - ${dir_source}/widgets/menu/logic.ts \ - ${dir_source}/widgets/sources/logic.ts \ - ${dir_source}/widgets/listview/logic.ts \ - ${dir_source}/widgets/weekview/logic.ts \ - ${dir_source}/widgets/mode_switcher/logic.ts \ - ${dir_source}/widgets/calendar_edit/logic.ts \ - ${dir_source}/widgets/event_edit/logic.ts \ ${dir_source}/overlay.ts \ - ${dir_source}/pages/caldav/logic.ts \ - ${dir_source}/pages/oidc_finish/logic.ts \ - ${dir_source}/pages/overview/logic.ts \ + $(wildcard ${dir_source}/widgets/*/logic.ts) \ + $(wildcard ${dir_source}/pages/*/logic.ts) \ ${dir_source}/main.ts @ ${cmd_log} "logic | compile …" @ ${cmd_mkdir} $(dir $@)
    {{label_weekday_monday}}{{label_weekday_tuesday}}{{label_weekday_wednesday}}{{label_weekday_thursday}}{{label_weekday_friday}}{{label_weekday_saturday}}{{label_weekday_sunday}}