Files
dees-catalog/ts_web/elements/dees-appui-mainselector.ts

212 lines
6.3 KiB
TypeScript
Raw Normal View History

2024-01-24 12:18:37 +01:00
import * as plugins from './00plugins.js';
import * as interfaces from './interfaces/index.js';
import { DeesContextmenu } from './dees-contextmenu.js';
import './dees-icon.js';
2024-01-24 12:18:37 +01:00
import {
DeesElement,
type TemplateResult,
property,
customElement,
html,
css,
cssManager,
} from '@design.estate/dees-element';
/**
* the property selector menu
* mainly used to select assets within in an organization
*/
@customElement('dees-appui-mainselector')
export class DeesAppuiMainselector extends DeesElement {
public static demo = () => html`
<dees-appui-mainselector
.selectionOptions=${[
{ key: 'Overview', iconName: 'home', action: () => console.log('Overview') },
{ key: 'Components', iconName: 'package', action: () => console.log('Components') },
{ key: 'Services', iconName: 'server', action: () => console.log('Services') },
{ key: 'Database', iconName: 'database', action: () => console.log('Database') },
{ key: 'Settings', iconName: 'settings', action: () => console.log('Settings') },
]}
></dees-appui-mainselector>
`;
2024-01-24 12:18:37 +01:00
// INSTANCE
@property({ type: Array })
public selectionOptions: (interfaces.ISelectionOption | { divider: true })[] = [
{ key: '⚠️ Please set selection options', action: () => console.warn('No selection options configured for mainselector') },
2024-01-24 12:18:37 +01:00
];
@property()
public selectedOption: interfaces.ISelectionOption = null;
public static styles = [
cssManager.defaultStyles,
css`
:host {
color: ${cssManager.bdTheme('#333', '#fff')};
2024-01-24 12:18:37 +01:00
position: relative;
display: block;
width: 100%;
max-width: 300px;
height: 100%;
background: ${cssManager.bdTheme('#fafafa', '#000000')};
border-right: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
2024-01-24 12:18:37 +01:00
}
.maincontainer {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
width: 100%;
}
.topbar {
position: absolute;
height: 40px;
2024-01-24 12:18:37 +01:00
width: 100%;
display: flex;
align-items: center;
border-bottom: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
2024-01-24 12:18:37 +01:00
}
.topbar .heading {
padding-left: 12px;
font-family: 'Geist Sans', sans-serif;
2024-01-24 12:18:37 +01:00
font-weight: 600;
font-size: 12px;
color: ${cssManager.bdTheme('#666', '#999')};
text-transform: uppercase;
letter-spacing: 0.5px;
2024-01-24 12:18:37 +01:00
}
.selectionOptions {
position: absolute;
top: 40px;
2024-01-24 12:18:37 +01:00
left: 0px;
right: 0px;
bottom: 0px;
overflow-y: auto;
font-family: 'Geist Sans', sans-serif;
font-size: 12px;
padding: 4px 0;
2024-01-24 12:18:37 +01:00
}
.selectionOptions .selectionOption {
cursor: default;
padding: 8px 12px;
margin: 0;
transition: background 0.1s;
display: flex;
align-items: center;
gap: 8px;
color: ${cssManager.bdTheme('#333', '#ccc')};
user-select: none;
2024-01-24 12:18:37 +01:00
}
.selectionOptions .selectionOption:hover {
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.04)', 'rgba(255, 255, 255, 0.08)')};
2024-01-24 12:18:37 +01:00
}
.selectionOptions .selectionOption:active {
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.12)')};
2024-01-24 12:18:37 +01:00
}
.selectionOptions .selectionOption.selectedOption {
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.12)')};
color: ${cssManager.bdTheme('#000', '#fff')};
font-weight: 500;
}
.selectionOptions .selectionOption.selectedOption::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: ${cssManager.bdTheme('#26a69a', '#26a69a')};
}
.selectionOption {
position: relative;
}
.selection-divider {
height: 1px;
background: ${cssManager.bdTheme('#e0e0e0', '#202020')};
margin: 4px 0;
2024-01-24 12:18:37 +01:00
}
`,
];
public render(): TemplateResult {
return html`
<style></style>
<div class="maincontainer">
<div class="topbar">
<div class="heading">Selector</div>
2024-01-24 12:18:37 +01:00
</div>
<div class="selectionOptions">
${this.selectionOptions.map((selectionOptionArg) => {
if ('divider' in selectionOptionArg && selectionOptionArg.divider) {
return html`<div class="selection-divider"></div>`;
}
const option = selectionOptionArg as interfaces.ISelectionOption;
2024-01-24 12:18:37 +01:00
return html`
<div
class="selectionOption ${this.selectedOption === option
2024-01-24 12:18:37 +01:00
? 'selectedOption'
: null}"
@click="${() => {
this.selectOption(option);
2024-01-24 12:18:37 +01:00
}}"
@contextmenu="${(eventArg: MouseEvent) => {
DeesContextmenu.openContextMenuWithOptions(eventArg, [
{
name: 'property settings',
action: async () => {},
iconName: 'gear',
},
]);
}}"
>
${option.iconName ? html`
<dees-icon .icon="${`lucide:${option.iconName}`}" style="font-size: 14px; opacity: 0.7;"></dees-icon>
` : ''}
<span style="flex: 1;">${option.key}</span>
2024-01-24 12:18:37 +01:00
</div>
`;
})}
</div>
</div>
`;
}
private selectOption(optionArg: interfaces.ISelectionOption) {
this.selectedOption = optionArg;
this.selectedOption.action();
// Emit option-select event
this.dispatchEvent(new CustomEvent('option-select', {
detail: { option: optionArg },
bubbles: true,
composed: true
}));
2024-01-24 12:18:37 +01:00
}
async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
await super.firstUpdated(_changedProperties);
if (this.selectionOptions && this.selectionOptions.length > 0) {
await this.updateComplete;
// Find first non-divider option
const firstOption = this.selectionOptions.find(option => !('divider' in option)) as interfaces.ISelectionOption;
if (firstOption) {
this.selectOption(firstOption);
}
}
2024-01-24 12:18:37 +01:00
}
}