mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-07 08:34:29 +01:00
Add new framework WIP
This commit is contained in:
parent
b3609b3f4a
commit
0bcb402b2e
@ -113,6 +113,12 @@ abstract class Framework extends Framework\Extra
|
|||||||
{
|
{
|
||||||
$GLOBALS['egw_info']['server']['template_set'] = 'pixelegg';
|
$GLOBALS['egw_info']['server']['template_set'] = 'pixelegg';
|
||||||
}
|
}
|
||||||
|
if($GLOBALS['egw_info']['user']['preferences']['common']['template_set'] !== $GLOBALS['egw_info']['server']['template_set'] &&
|
||||||
|
class_exists($class = $GLOBALS['egw_info']['user']['preferences']['common']['template_set'] . '_framework')
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$GLOBALS['egw_info']['server']['template_set'] = $GLOBALS['egw_info']['user']['preferences']['common']['template_set'];
|
||||||
|
}
|
||||||
// then jdots aka Stylite template
|
// then jdots aka Stylite template
|
||||||
if (file_exists(EGW_SERVER_ROOT.'/jdots') && empty($GLOBALS['egw_info']['server']['template_set']))
|
if (file_exists(EGW_SERVER_ROOT.'/jdots') && empty($GLOBALS['egw_info']['server']['template_set']))
|
||||||
{
|
{
|
||||||
|
92
kdots/head.tpl
Normal file
92
kdots/head.tpl
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<!-- BEGIN head --><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xml:lang="{lang_code}" xmlns="http://www.w3.org/1999/xhtml"{dir_code} data-darkmode={darkmode}>
|
||||||
|
<head>
|
||||||
|
<title>{website_title}</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset={charset}"/>
|
||||||
|
<meta name="keywords" content="EGroupware"/>
|
||||||
|
<meta name="description" content="EGroupware"/>
|
||||||
|
<meta name="keywords" content="EGroupware"/>
|
||||||
|
<meta name="copyright" content="EGroupware GmbH https://www.egroupware.org (c) 2020"/>
|
||||||
|
<meta name="language" content="{lang_code}"/>
|
||||||
|
<meta name="author" content="EGroupware GmbH https://www.egroupware.org"/>
|
||||||
|
{meta_robots}
|
||||||
|
<link rel="manifest" href="{webserver_url}/manifest.json"/>
|
||||||
|
<link rel="icon" href="{img_icon}" type="image/x-ico"/>
|
||||||
|
<link rel="shortcut icon" href="{img_shortcut}"/>
|
||||||
|
<link rel="stylesheet" href="{webserver_url}/api/js/offline/themes/offline-theme-slide.css">
|
||||||
|
<link rel="stylesheet" href="{webserver_url}/api/js/offline/themes/offline-language-{lang_code}.css">
|
||||||
|
<script src="{webserver_url}/api/js/offline/offline.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="{webserver_url}/node_modules/@shoelace-style/shoelace/dist/themes/light.css"/>
|
||||||
|
<link rel="stylesheet" href="{webserver_url}/node_modules/@shoelace-style/shoelace/dist/themes/dark.css"/>
|
||||||
|
<link rel="stylesheet" href="{webserver_url}/kdots/assets/styles/framework.css">
|
||||||
|
{css_file}
|
||||||
|
<style type="text/css">
|
||||||
|
{app_css}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
{firstload_animation_style}
|
||||||
|
</style>
|
||||||
|
<script type="module" src="{webserver_url}/kdots/js/app.min.js"></script>
|
||||||
|
{java_script}
|
||||||
|
</head>
|
||||||
|
<body {body_tags}>
|
||||||
|
{include_wz_tooltip}
|
||||||
|
<!-- END head -->
|
||||||
|
<!-- BEGIN framework -->
|
||||||
|
<egw-framework id="egw_fw_basecontainer" class="sl-theme-light"
|
||||||
|
application-list="{application-list}"
|
||||||
|
>
|
||||||
|
<a slot="logo" href="{logo_url}" target="_blank"><img src="{logo_header}" title="{logo_title}" alt="Site logo"/></a>
|
||||||
|
<div slot="header-right" id="egw_fw_topmenu_info_items">
|
||||||
|
{topmenu_info_items}
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fake apps -->
|
||||||
|
<sl-icon-button name="backpack" slot="header" label="Backpack application"></sl-icon-button>
|
||||||
|
<sl-icon-button name="airplane" slot="header" label="Airplaine application"></sl-icon-button>
|
||||||
|
<sl-icon-button name="mortarboard" slot="header" label="Mortarboard application"></sl-icon-button>
|
||||||
|
<et2-image src="mail/navbar" slot="header"></et2-image>
|
||||||
|
|
||||||
|
<div slot="aside" id="egw_fw_sidebar_r"></div>
|
||||||
|
|
||||||
|
<!-- Fake app -->
|
||||||
|
<egw-app name="fake app">
|
||||||
|
<div slot="banner">Something inside the app - main</div>
|
||||||
|
</egw-app>
|
||||||
|
</egw-framework>
|
||||||
|
|
||||||
|
|
||||||
|
{hook_after_navbar}
|
||||||
|
|
||||||
|
<!-- END framework -->
|
||||||
|
<!--
|
||||||
|
|
||||||
|
<div id="egw_fw_basecontainer" lang="{lang_code}">
|
||||||
|
<div id="egw_fw_header">
|
||||||
|
<div id="egw_fw_topmenu">
|
||||||
|
<div id="egw_fw_topmenu_items">
|
||||||
|
{topmenu_items}
|
||||||
|
<div class="timezone">
|
||||||
|
{user_info}
|
||||||
|
</div>
|
||||||
|
{powered_by}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="egw_fw_sidebar">
|
||||||
|
<div id="egw_fw_sidemenu"></div>
|
||||||
|
<div id="egw_fw_splitter"></div>
|
||||||
|
</div>
|
||||||
|
<div id="egw_fw_main">
|
||||||
|
<div id="egw_fw_tabs">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="egw_fw_firstload">
|
||||||
|
{firstload_animation}
|
||||||
|
</div>
|
||||||
|
<!-- END framework -->
|
119
kdots/inc/class.kdots_framework.inc.php
Normal file
119
kdots/inc/class.kdots_framework.inc.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use EGroupware\Api;
|
||||||
|
|
||||||
|
class kdots_framework extends Api\Framework\Ajax
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Appname used for everything but JS includes
|
||||||
|
*/
|
||||||
|
const APP = 'kdots';
|
||||||
|
/**
|
||||||
|
* Appname used to include javascript code
|
||||||
|
*/
|
||||||
|
const JS_INCLUDE_APP = 'kdots';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable to use this template sets login.tpl for login page
|
||||||
|
*/
|
||||||
|
const LOGIN_TEMPLATE_SET = true;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get header as array to eg. set as vars for a template (from idots' head.inc.php)
|
||||||
|
*
|
||||||
|
* @param array $extra =array() extra attributes passed as data-attribute to egw.js
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
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');
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function topmenu(array $vars, array $apps)
|
||||||
|
{
|
||||||
|
$this->topmenu_items = $this->topmenu_info_items = array();
|
||||||
|
|
||||||
|
parent::topmenu($vars, $apps);
|
||||||
|
|
||||||
|
$vars['topmenu_items'] = "<sl-menu>" . implode("\n", $this->topmenu_items) . "</sl-menu>";
|
||||||
|
$vars['topmenu_info_items'] = '';
|
||||||
|
foreach($this->topmenu_info_items as $id => $item)
|
||||||
|
{
|
||||||
|
switch($id)
|
||||||
|
{
|
||||||
|
case 'user_avatar':
|
||||||
|
$vars['topmenu_info_items'] .= "<sl-dropdown class=\"topmenu_info_item\" id=\"topmenu_info_{$id}\" aria-label='" . lang("User menu") . "' tabindex='0'><div slot='trigger'>$item</div> {$vars['topmenu_items']}</sl-dropdown>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$vars['topmenu_info_items'] .= '<button class="topmenu_info_item"' .
|
||||||
|
(is_numeric($id) ? '' : ' id="topmenu_info_' . $id . '"') . '>' . $item . "</button>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->topmenu_items = $this->topmenu_info_items = null;
|
||||||
|
|
||||||
|
return $vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add info items to the topmenu template class to be displayed
|
||||||
|
*
|
||||||
|
* @param string $content Api\Html of item
|
||||||
|
* @param string $id = null
|
||||||
|
* @access protected
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function _add_topmenu_info_item($content, $id = null)
|
||||||
|
{
|
||||||
|
if(strpos($content, 'menuaction=admin.admin_accesslog.sessions') !== false)
|
||||||
|
{
|
||||||
|
$content = preg_replace('/href="([^"]+)"/', "href=\"javascript:egw_link_handler('\\1','admin')\"", $content);
|
||||||
|
}
|
||||||
|
if($id)
|
||||||
|
{
|
||||||
|
$this->topmenu_info_items[$id] = $content;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->topmenu_info_items[] = $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add menu items to the topmenu template class to be displayed
|
||||||
|
*
|
||||||
|
* @param array $app application data
|
||||||
|
* @param mixed $alt_label string with alternative menu item label default value = null
|
||||||
|
* @param string $urlextra string with alternate additional code inside <a>-tag
|
||||||
|
* @access protected
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function _add_topmenu_item(array $app_data, $alt_label = null)
|
||||||
|
{
|
||||||
|
switch($app_data['name'])
|
||||||
|
{
|
||||||
|
case 'manual':
|
||||||
|
$app_data['url'] = "javascript:callManual();";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strpos($app_data['url'], 'logout.php') === false && substr($app_data['url'], 0, 11) != 'javascript:')
|
||||||
|
{
|
||||||
|
$app_data['url'] = "javascript:egw_link_handler('" . $app_data['url'] . "','" .
|
||||||
|
(isset($GLOBALS['egw_info']['user']['apps'][$app_data['name']]) ?
|
||||||
|
$app_data['name'] : 'about') . "')";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$id = $app_data['id'] ? $app_data['id'] : ($app_data['name'] ? $app_data['name'] : $app_data['title']);
|
||||||
|
$title = htmlspecialchars($alt_label ? $alt_label : $app_data['title']);
|
||||||
|
$this->topmenu_items[] = '<sl-menu-item id="topmenu_' . $id . '" value="' . htmlspecialchars($app_data['url']) . '" title="' . $app_data['title'] . '">' . $title . '</sl-menu-item>';
|
||||||
|
}
|
||||||
|
}
|
69
kdots/js/EgwApp.styles.ts
Normal file
69
kdots/js/EgwApp.styles.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import {css} from 'lit';
|
||||||
|
|
||||||
|
export default css`
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host > * {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw_app__left {
|
||||||
|
grid-area: left;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw_app__right {
|
||||||
|
grid-area: right;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw_app__main {
|
||||||
|
grid-area: main;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw_app__header {
|
||||||
|
grid-area: header;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.egw_fw_app__footer {
|
||||||
|
grid-area: footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 500px) {
|
||||||
|
:host {
|
||||||
|
grid-template-columns: [start left] fit-content(20%) [main] 1fr [right] fit-content(50%) [end];
|
||||||
|
grid-template-rows: [header] fit-content(2em) [main] 1fr [footer bottom] fit-content(2em) [end];
|
||||||
|
grid-template-areas:
|
||||||
|
"left-header header right-header"
|
||||||
|
"left main right"
|
||||||
|
"left-footer footer right-footer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
:host {
|
||||||
|
grid-template-areas:
|
||||||
|
"header"
|
||||||
|
"main"
|
||||||
|
"left right"
|
||||||
|
}
|
||||||
|
|
||||||
|
[slot="footer"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
86
kdots/js/EgwApp.ts
Normal file
86
kdots/js/EgwApp.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import {css, html, LitElement} from "lit";
|
||||||
|
import {customElement} from "lit/decorators/custom-element.js";
|
||||||
|
import "@shoelace-style/shoelace/dist/components/split-panel/split-panel.js";
|
||||||
|
import {property} from "lit/decorators/property.js";
|
||||||
|
|
||||||
|
import styles from "./EgwApp.styles";
|
||||||
|
import {state} from "lit/decorators/state.js";
|
||||||
|
|
||||||
|
@customElement('egw-app')
|
||||||
|
//@ts-ignore
|
||||||
|
export class EgwApp extends LitElement
|
||||||
|
{
|
||||||
|
static get styles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
styles,
|
||||||
|
|
||||||
|
// TEMP STUFF
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
--placeholder-background-color: #e97234;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
font-size: 200%;
|
||||||
|
text-align: center;
|
||||||
|
background-color: var(--placeholder-background-color, silver);
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder:after {
|
||||||
|
content: " (placeholder)";
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="left"] .placeholder, [class*="right"] .placeholder {
|
||||||
|
background-color: color-mix(in lch, var(--placeholder-background-color), rgba(1, 1, 1, .5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="footer"] .placeholder {
|
||||||
|
background-color: color-mix(in lch, var(--placeholder-background-color), rgba(1, 1, 1, .05));
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
name = "Application name";
|
||||||
|
|
||||||
|
@state()
|
||||||
|
leftCollapsed = false;
|
||||||
|
|
||||||
|
get egw()
|
||||||
|
{
|
||||||
|
return window.egw ?? this.parentElement.egw ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
render()
|
||||||
|
{
|
||||||
|
return html`
|
||||||
|
<div class="egw_fw_app__name" part="name">
|
||||||
|
<sl-icon-button name="${this.leftCollapsed ? "chevron-double-right" : "chevron-double-left"}"
|
||||||
|
label="${this.egw?.lang("Hide area")}"
|
||||||
|
@click=${() => {this.leftCollapsed = !this.leftCollapsed}}
|
||||||
|
></sl-icon-button>
|
||||||
|
<h2>${this.egw?.lang(this.name) ?? this.name}</h2>
|
||||||
|
</div>
|
||||||
|
<aside class="egw_fw_app__left" part="left">
|
||||||
|
<slot name="left"><span class="placeholder">left</span></slot>
|
||||||
|
</aside>
|
||||||
|
<aside class="egw_fw_app__right" part="right">
|
||||||
|
<slot name="right"><span class="placeholder">right</span></slot>
|
||||||
|
</aside>
|
||||||
|
<header class="egw_fw_app__header" part="header">
|
||||||
|
<slot name="main-header"><span class="placeholder"> ${this.name} main-header</span></slot>
|
||||||
|
</header>
|
||||||
|
<main class="egw_fw_app__main" part="main"
|
||||||
|
aria-label="${this.name}" tabindex="0">
|
||||||
|
<slot><span class="placeholder">main</span></slot>
|
||||||
|
</main>
|
||||||
|
<footer class="egw_fw_app__footer" part="footer">
|
||||||
|
<slot name="footer"><span class="placeholder">main-footer</span></slot>
|
||||||
|
</footer>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
112
kdots/js/EgwFramework.styles.ts
Normal file
112
kdots/js/EgwFramework.styles.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import {css} from 'lit';
|
||||||
|
|
||||||
|
export default css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5em 0.1em;
|
||||||
|
border: 1px dotted;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default > * {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__banner {
|
||||||
|
grid-area: banner;
|
||||||
|
grid-column-start: banner-start;
|
||||||
|
grid-column-end: banner-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__header {
|
||||||
|
grid-area: header;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To use the sl-split-panel, we need it to have its own space & nest stuff inside */
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__divider {
|
||||||
|
grid-column-start: sidemenu-start;
|
||||||
|
grid-column-end: status-start;
|
||||||
|
grid-row-start: main-header;
|
||||||
|
grid-row-end: footer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default sl-split-panel {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default sl-split-panel::part(divider) {
|
||||||
|
color: var(--sl-color-primary-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__sidemenu {
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__status {
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__main-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: [start] 1fr [end];
|
||||||
|
grid-template-rows: [top main-header] fit-content(2em) [main] 1fr [main-footer] fit-content(0px) [ bottom]
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__main {
|
||||||
|
grid-column-start: start;
|
||||||
|
grid-column-end: end;
|
||||||
|
grid-row-start: main;
|
||||||
|
grid-row-end: main;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__main-header {
|
||||||
|
grid-column-start: start;
|
||||||
|
grid-column-end: end;
|
||||||
|
grid-row-start: main-header;
|
||||||
|
grid-row-end: main-header
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__main-footer {
|
||||||
|
grid-column-start: start;
|
||||||
|
grid-column-end: end;
|
||||||
|
grid-row-start: main-footer;
|
||||||
|
grid-row-end: main-footer
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__layout-default .egw_fw__footer {
|
||||||
|
grid-area: footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media (min-width: 500px) {
|
||||||
|
.egw_fw__layout-default {
|
||||||
|
grid-template-columns: [start sidemenu-start banner-start header-start footer-start] 200px [sidemenu-end main-start] 1fr [main-end] fit-content(2em) [header-end banner-end end];
|
||||||
|
grid-template-rows: [top banner] fit-content(2em) [header] fit-content(2em) [ main-header] fit-content(2em) [main] 1fr [main-footer] fit-content(2em) [footer bottom] fit-content(2em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actual styles */
|
||||||
|
|
||||||
|
.egw_fw__header sl-icon-button {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
`
|
131
kdots/js/EgwFramework.ts
Normal file
131
kdots/js/EgwFramework.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import {css, html, LitElement} from "lit";
|
||||||
|
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";
|
||||||
|
|
||||||
|
@customElement('egw-framework')
|
||||||
|
//@ts-ignore
|
||||||
|
export class EgwFramework extends LitElement
|
||||||
|
{
|
||||||
|
static get styles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
styles,
|
||||||
|
|
||||||
|
// TEMP STUFF
|
||||||
|
css`
|
||||||
|
.placeholder {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
font-size: 200%;
|
||||||
|
text-align: center;
|
||||||
|
background-color: var(--placeholder-background-color, silver);
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder:after {
|
||||||
|
content: " (placeholder)";
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__base {
|
||||||
|
--placeholder-background-color: #75bd20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__footer .placeholder {
|
||||||
|
background-color: hsl(182, 58%, 62%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__main-wrapper {
|
||||||
|
--placeholder-background-color: #e97234;
|
||||||
|
}
|
||||||
|
|
||||||
|
.egw_fw__status .placeholder {
|
||||||
|
writing-mode: vertical-rl;
|
||||||
|
text-orientation: mixed;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="left"] .placeholder {
|
||||||
|
background-color: color-mix(in lch, var(--placeholder-background-color), rgba(1, 1, 1, .5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="footer"] .placeholder {
|
||||||
|
background-color: color-mix(in lch, var(--placeholder-background-color), rgba(1, 1, 1, .05));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::slotted(div#egw_fw_sidebar_r) {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
layout = "default";
|
||||||
|
|
||||||
|
@property({type: Array})
|
||||||
|
applicationList = [];
|
||||||
|
|
||||||
|
get egw()
|
||||||
|
{
|
||||||
|
return window.egw ?? {
|
||||||
|
app_name: () => "",
|
||||||
|
lang: (t) => t,
|
||||||
|
preference: (n, app) => ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render()
|
||||||
|
{
|
||||||
|
const statusPosition = this.egw?.preference("statusPosition", this.egw?.app_name()) ?? "36";
|
||||||
|
|
||||||
|
const classes = {
|
||||||
|
"egw_fw__base": true
|
||||||
|
}
|
||||||
|
classes[`egw_fw__layout-${this.layout}`] = true;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class=${classMap(classes)} part="base">
|
||||||
|
<div class="egw_fw__banner" part="banner" role="banner">
|
||||||
|
<slot name="banner"><span class="placeholder">Banner</span></slot>
|
||||||
|
</div>
|
||||||
|
<header class="egw_fw__header" part="header">
|
||||||
|
<slot name="logo"></slot>
|
||||||
|
<sl-dropdown class="egw_fw__app_list">
|
||||||
|
<sl-icon-button slot="trigger" name="grid-3x3-gap"
|
||||||
|
label="${this.egw.lang("Application list")}"
|
||||||
|
aria-description="${this.egw.lang("Activate for a list of applications")}"
|
||||||
|
></sl-icon-button>
|
||||||
|
${repeat(this.applicationList, (app) => html`
|
||||||
|
<et2-image src="${app.icon}" aria-label="${app.title}"></et2-image>`)}
|
||||||
|
</sl-dropdown>
|
||||||
|
|
||||||
|
<slot name="header"><span class="placeholder">header</span></slot>
|
||||||
|
<slot name="header-right"><span class="placeholder">header-right</span></slot>
|
||||||
|
</header>
|
||||||
|
<div class="egw_fw__divider">
|
||||||
|
<sl-split-panel part="status-split" position-in-pixels="${statusPosition}" primary="end"
|
||||||
|
snap="150px 45px 0px"
|
||||||
|
snap-threshold="40"
|
||||||
|
aria-label="Side menu resize">
|
||||||
|
|
||||||
|
<main slot="start" part="main">
|
||||||
|
<slot></slot>
|
||||||
|
</main>
|
||||||
|
<sl-icon slot="divider" name="grip-vertical"></sl-icon>
|
||||||
|
<aside slot="end" class="egw_fw__status" part="status">
|
||||||
|
<slot name="status"><span class="placeholder">status</span></slot>
|
||||||
|
</aside>
|
||||||
|
</sl-split-panel>
|
||||||
|
</div>
|
||||||
|
<footer class="egw_fw__footer" part="footer">
|
||||||
|
<slot name="footer"><span class="placeholder">footer</span></slot>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
17
kdots/js/app.ts
Normal file
17
kdots/js/app.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* app.ts is auto-built
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./EgwFramework";
|
||||||
|
import "./EgwApp";
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () =>
|
||||||
|
{
|
||||||
|
/* Set up listener on avatar menu */
|
||||||
|
const avatarMenu = document.querySelector("#topmenu_info_user_avatar");
|
||||||
|
avatarMenu.addEventListener("sl-select", (e : CustomEvent) =>
|
||||||
|
{
|
||||||
|
window.egw.open_link(e.detail.item.value);
|
||||||
|
});
|
||||||
|
});
|
32
kdots/setup/setup.inc.php
Normal file
32
kdots/setup/setup.inc.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware: Standard template
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['name'] = 'kdots';
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['title'] = 'Kdots WIP ';
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['version'] = '24.1';
|
||||||
|
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['author'] = array(
|
||||||
|
array('name' => 'EGroupware GmbH', 'url' => 'http://www.egroupware.org/'),
|
||||||
|
);
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['license'] = 'GPL';
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['maintainer'] = array(
|
||||||
|
array('name' => 'EGroupware GmbH', 'url' => 'http://www.egroupware.org/')
|
||||||
|
);
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['description'] = "WIP framework of EGroupware.";
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['windowed'] = true;
|
||||||
|
|
||||||
|
// specify (different) labels for default themes
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['themes'] = array(
|
||||||
|
'default' => 'Standard'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dependencies for this template to work
|
||||||
|
$GLOBALS['egw_info']['template']['kdots']['depends'][] = array(
|
||||||
|
'appname' => 'api',
|
||||||
|
'versions' => array('23.1')
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user