diff --git a/kdots/assets/styles/framework.less b/kdots/assets/styles/framework.less new file mode 100644 index 0000000000..9476b081b0 --- /dev/null +++ b/kdots/assets/styles/framework.less @@ -0,0 +1,203 @@ +html, body { + width: 100vw; + height: 100vh; + overflow: clip; + padding: 0px; + margin: 0px; +} + +egw-framework#egw_fw_basecontainer { + --icon-size: 32px; + --sl-tooltip-arrow-size: 0; + + /* Internals */ + + &::part(status-split) { + --max: 150px; + } + + &::part(header) { + background-color: var(--primary-background-color); + color: var(--sl-color-neutral-0); + gap: var(--sl-spacing-medium); + + font-size: var(--icon-size); + + } + + /* Content slotted inside */ + + [slot="logo"] img { + max-width: 220px; + max-height: var(--icon-size); + display: block; + text-align: center; + } + + sl-icon-button[slot="header"], et2-image[slot="header"] { + font-size: var(--icon-size); + color: inherit + } + + + div#egw_fw_toggler { + position: initial; + display: none; + } + + #egw_fw_topmenu_info_items { + position: relative; + order: 99; + margin-left: auto; + display: flex; + + .topmenu_info_item { + min-width: 1em; + min-height: 1em; + } + } + + div#egw_fw_sidebar_r { + position: initial; + top: initial; + } + + .egw_fw_ui_sidemenu_entry_header { + display: flex; + gap: var(--sl-spacing-medium); + padding-left: 1em; + } +} + +egw-app { + &::part(name) { + align-items: center; + } +} + +/*** HEADER ***/ +#egw_fw_topmenu_info_items { + display: flex !important; + flex-direction: row-reverse; + height: var(--icon-size); + background-color: #fbfbfb; + + & > * { + border: none; + background: transparent; + } + + et2-avatar { + --size: var(--icon-size); + } + + .topmenu_info_item { + height: var(--icon-size); + width: var(--icon-size); + border-left: 1px solid #bfc0bf; + display: inline-block; + padding-left: 0px; + background-size: 20px; + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + + &:hover { + background-color: var(--sl-input-background-color-hover); + } + } + + #topmenu_info_timer { + order: 1; + position: relative; + + #topmenu_timer { + position: relative; + top: 10px !important; + display: block; + height: 45px; + width: 45px; + } + + &:hover { + cursor: pointer; + } + + &:before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url(../../../timesheet/templates/default/images/navbar.svg); + background-repeat: no-repeat; + background-size: 32px; + background-position: center center; + filter: opacity(0.3); + } + } + + ul a#topmenu_cats { + background-image: url(../../../api/templates/default/images/topmenu_items/category.svg); + } + + ul a#topmenu_password { + background-image: url(../../../api/templates/default/images/topmenu_items/password.svg); + } + + ul a#topmenu_search { + background-image: url(../../../api/templates/default/images/topmenu_items/search.svg); + } + + ul a#topmenu_prefs { + background-image: url(../../../api/templates/default/images/topmenu_items/setup.svg); + } + + ul a#topmenu_home { + background-image: url(../../../api/templates/default/images/topmenu_items/home.svg); + } + + ul a#topmenu_acl { + background-image: url(../../../api/templates/default/images/topmenu_items/access.svg); + } + + ul a#topmenu_useraccount { + background-image: url(../../../api/templates/default/images/accounts.svg); + background-repeat: no-repeat; + background-size: 18px; + background-position-x: -2px; + } + + ul a#topmenu_calls { + background-image: url(../../../api/templates/default/images/phone.svg); + background-repeat: no-repeat; + background-position-x: -2px; + } +} + +#topmenu_info_logout { + background-image: url(../../../api/templates/default/images/logout.svg); + + a { + width: 45px; + height: 45px; + display: inline-block; + } +} + +#topmenu_info_print_title { + background-image: url(../../../api/templates/default/images/print.svg); + + span { + width: 45px; + height: 45px; + display: inline-block; + } +} + +/*** END HEADER ***/ + +div#egw_fw_basecontainer { + display: none; +} \ No newline at end of file diff --git a/kdots/head.tpl b/kdots/head.tpl index 565df81d30..09dc273c55 100644 --- a/kdots/head.tpl +++ b/kdots/head.tpl @@ -44,13 +44,7 @@ - - - - - - - +
diff --git a/kdots/inc/class.kdots_framework.inc.php b/kdots/inc/class.kdots_framework.inc.php index c37276236d..5fb0eff7e4 100644 --- a/kdots/inc/class.kdots_framework.inc.php +++ b/kdots/inc/class.kdots_framework.inc.php @@ -28,7 +28,7 @@ class kdots_framework extends Api\Framework\Ajax protected function _get_header(array $extra = array()) { $data = parent::_get_header($extra); - $data['applicationlist'] = htmlentities(json_encode($extra['navbar-apps'], JSON_HEX_QUOT | JSON_HEX_AMP), ENT_QUOTES, 'UTF-8'); + $data['application-list'] = htmlentities(json_encode($extra['navbar-apps'], JSON_HEX_QUOT | JSON_HEX_AMP), ENT_QUOTES, 'UTF-8'); return $data; } diff --git a/kdots/js/EgwFramework.styles.ts b/kdots/js/EgwFramework.styles.ts index bdaa01a017..a4e3d206b4 100644 --- a/kdots/js/EgwFramework.styles.ts +++ b/kdots/js/EgwFramework.styles.ts @@ -6,6 +6,8 @@ export default css` width: 100vw; height: 100vh; position: relative; + + --icon-size: 32px; } .egw_fw__layout-default { @@ -109,4 +111,35 @@ export default css` .egw_fw__header sl-icon-button { color: inherit; } + + .egw_fw__app_list::part(panel) { + display: grid; + grid-template-columns: repeat(5, 1fr); + background-color: var(--sl-color-neutral-0); + font-size: var(--icon-size); + } + + .egw_fw__open_applications et2-image { + height: var(--icon-size); + width: var(--icon-size); + } + + .egw_fw__open_applications sl-tab::part(base) { + padding: 0px; + font-size: var(--icon-size); + } + + .egw_fw__open_applications sl-tab::part(close-button) { + visibility: hidden; + margin-inline-start: var(--sl-spacing-2x-small); + color: var(--sl-color-neutral-100); + } + + .egw_fw__open_applications sl-tab et2-image { + padding: var(--sl-spacing-small) var(--sl-spacing-3x-small); + } + + .egw_fw__open_applications sl-tab:hover::part(close-button) { + visibility: visible; + } ` \ No newline at end of file diff --git a/kdots/js/EgwFramework.ts b/kdots/js/EgwFramework.ts index 06e45e5779..e49d91d442 100644 --- a/kdots/js/EgwFramework.ts +++ b/kdots/js/EgwFramework.ts @@ -3,10 +3,33 @@ import {customElement} from "lit/decorators/custom-element.js"; import {property} from "lit/decorators/property.js"; import {classMap} from "lit/directives/class-map.js"; import "@shoelace-style/shoelace/dist/components/split-panel/split-panel.js"; - import styles from "./EgwFramework.styles"; import {repeat} from "lit/directives/repeat.js"; +/** + * @summary Accessable, webComponent-based EGroupware framework + * + * @dependency sl-dropdown + * @dependency sl-icon-button + * + * @slot - Current application + * @slot banner - Very top, used for things like persistant, system wide messages. Normally hidden. + * @slot header - Top of page, contains logo, app icons. + * @slot header-right - Top right, contains user info / actions. + * @slot status - Home of the status app, it is limited in size and can be resized and hidden. + * @slot footer - Very bottom. Normally hidden. + * * + * @csspart base - Wraps it all. + * @csspart banner - + * @csspart header - + * @csspart open-applications - Tab group that has the currently open applications + * @csspart status-split - Status splitter + * @csspart main + * @csspart status + * @csspart footer + * + * @cssproperty [--icon-size=32] - Height of icons used in the framework + */ @customElement('egw-framework') //@ts-ignore export class EgwFramework extends LitElement @@ -67,7 +90,7 @@ export class EgwFramework extends LitElement @property() layout = "default"; - @property({type: Array}) + @property({type: Array, attribute: "application-list"}) applicationList = []; get egw() @@ -79,9 +102,47 @@ export class EgwFramework extends LitElement }; } + /** + * An application tab is chosen, show the app + * + * @param e + * @protected + */ + protected handleApplicationTabShow(e) + { + + } + + /** + * Renders one application into the 9-dots application menu + * + * @param app + * @returns {TemplateResult<1>} + * @protected + */ + protected _applicationListAppTemplate(app) + { + return html` + + + `; + } + + protected _applicationTabTemplate(app) + { + return html` + + + + + `; + } + render() { - const statusPosition = this.egw?.preference("statusPosition", this.egw?.app_name()) ?? "36"; + const iconSize = getComputedStyle(this).getPropertyValue("--icon-size"); + const statusPosition = this.egw?.preference("statusPosition", "common") ?? parseInt(iconSize) ?? "36"; const classes = { "egw_fw__base": true @@ -95,24 +156,26 @@ export class EgwFramework extends LitElement
- + - ${repeat(this.applicationList, (app) => html` - `)} + ${repeat(this.applicationList, (app) => this._applicationListAppTemplate(app))} - + + ${repeat(this.applicationList.filter(app => app.opened), (app) => this._applicationTabTemplate(app))} + header header-right
-