feat(dees-button,dees-statsgrid): add unified icon property and icon-position support to dees-button; add partition and disk tile types to dees-statsgrid

This commit is contained in:
2026-01-13 20:45:50 +00:00
parent 1982c40337
commit 5dd0367df0
22 changed files with 639 additions and 38 deletions

View File

@@ -68,6 +68,12 @@ export class DeesButton extends DeesElement {
})
accessor insideForm: boolean = false;
@property({ type: String, reflect: true })
accessor icon: string;
@property({ type: String, reflect: true })
accessor iconPosition: 'left' | 'right' = 'left';
constructor() {
super();
}
@@ -340,9 +346,62 @@ export class DeesButton extends DeesElement {
height: 18px;
}
/* Text alignment */
.textbox {
display: flex;
align-items: center;
}
`,
];
/**
* Extracts icon and text from light DOM and sets properties
*/
private extractLightDom(): void {
const iconElement = this.querySelector('dees-icon') as any;
// Get all text content from light DOM
const textContent = Array.from(this.childNodes)
.filter(node => node.nodeType === Node.TEXT_NODE)
.map(node => node.textContent?.trim())
.filter(Boolean)
.join(' ');
if (textContent && !this.text) {
this.text = textContent;
}
if (iconElement) {
// Get icon value
const iconValue = iconElement.icon || iconElement.getAttribute('icon') ||
(iconElement.iconFA ? `fa:${iconElement.iconFA}` : null);
if (iconValue) {
// Determine position based on DOM order
const children = Array.from(this.childNodes);
const iconIndex = children.indexOf(iconElement);
const textNodes = children.filter(node =>
node.nodeType === Node.TEXT_NODE && node.textContent?.trim()
);
if (textNodes.length > 0) {
const firstTextIndex = children.indexOf(textNodes[0]);
this.iconPosition = iconIndex < firstTextIndex ? 'left' : 'right';
}
// Set the icon property
this.icon = iconValue;
}
// Remove the light DOM icon element
iconElement.remove();
}
// Clear all remaining light DOM
this.innerHTML = '';
}
public render(): TemplateResult {
// Map old types to new types for backward compatibility
const typeMap: {[key: string]: string} = {
@@ -351,10 +410,20 @@ export class DeesButton extends DeesElement {
'discreet': 'outline',
'big': 'default' // Will use size instead
};
const actualType = typeMap[this.type] || this.type;
const actualSize = this.type === 'big' ? 'lg' : this.size;
const leftIcon = this.iconPosition === 'left' && this.icon
? html`<dees-icon .icon=${this.icon}></dees-icon>`
: '';
const rightIcon = this.iconPosition === 'right' && this.icon
? html`<dees-icon .icon=${this.icon}></dees-icon>`
: '';
// For icon-only buttons, hide the textbox
const isIconOnly = actualSize === 'icon' && this.icon;
return html`
<div
class="button ${this.isHidden ? 'hidden' : ''} ${actualType} size-${actualSize} ${this.status} ${this.disabled
@@ -363,13 +432,15 @@ export class DeesButton extends DeesElement {
@click="${this.dispatchClick}"
>
${this.status === 'normal' ? html``: html`
<dees-spinner
.bnw=${true}
<dees-spinner
.bnw=${true}
status="${this.status}"
size="${actualSize === 'sm' ? 14 : actualSize === 'lg' ? 18 : 16}"
></dees-spinner>
`}
<div class="textbox">${this.text || html`<slot>Button</slot>`}</div>
${leftIcon}
${isIconOnly ? '' : html`<div class="textbox">${this.text || 'Button'}</div>`}
${rightIcon}
</div>
`;
}
@@ -390,6 +461,7 @@ export class DeesButton extends DeesElement {
}
public async firstUpdated() {
// Don't set default text here as it interferes with slotted content
// Extract light DOM content (icon + text) and set as properties
this.extractLightDom();
}
}