feat(elements): add upladmin-option-card component and migrate option/status UIs to use it; refactor monitor form multitoggle subscriptions and event handling; improve theme color handling and dark-mode styles; add demos, Playwright snapshots, and migration plan
This commit is contained in:
1
ts_web/elements/upladmin-option-card/index.ts
Normal file
1
ts_web/elements/upladmin-option-card/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './upladmin-option-card.js';
|
||||
@@ -0,0 +1,118 @@
|
||||
import { html, css, cssManager } from '@design.estate/dees-element';
|
||||
import type { UpladminOptionCard } from './upladmin-option-card.js';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<style>
|
||||
.demo-container {
|
||||
padding: 24px;
|
||||
background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
|
||||
min-height: 100vh;
|
||||
}
|
||||
.demo-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.demo-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.demo-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
<div class="demo-container">
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Severity Variants</div>
|
||||
<div class="demo-grid">
|
||||
<upladmin-option-card
|
||||
variant="critical"
|
||||
icon="lucide:AlertCircle"
|
||||
label="Critical"
|
||||
description="Severe impact"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="major"
|
||||
icon="lucide:AlertTriangle"
|
||||
label="Major"
|
||||
description="Significant impact"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="minor"
|
||||
icon="lucide:Info"
|
||||
label="Minor"
|
||||
description="Limited impact"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="maintenance"
|
||||
icon="lucide:Wrench"
|
||||
label="Maintenance"
|
||||
description="Scheduled work"
|
||||
selected
|
||||
></upladmin-option-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Status Variants</div>
|
||||
<div class="demo-grid">
|
||||
<upladmin-option-card
|
||||
variant="investigating"
|
||||
icon="lucide:Search"
|
||||
label="Investigating"
|
||||
description="Looking into it"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="identified"
|
||||
icon="lucide:Target"
|
||||
label="Identified"
|
||||
description="Root cause found"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="monitoring"
|
||||
icon="lucide:Eye"
|
||||
label="Monitoring"
|
||||
description="Fix applied"
|
||||
selected
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="resolved"
|
||||
icon="lucide:CheckCircle"
|
||||
label="Resolved"
|
||||
description="Issue fixed"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="postmortem"
|
||||
icon="lucide:FileText"
|
||||
label="Postmortem"
|
||||
description="Analysis complete"
|
||||
></upladmin-option-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">States</div>
|
||||
<div class="demo-grid">
|
||||
<upladmin-option-card
|
||||
variant="primary"
|
||||
icon="lucide:Star"
|
||||
label="Normal"
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="primary"
|
||||
icon="lucide:Star"
|
||||
label="Selected"
|
||||
selected
|
||||
></upladmin-option-card>
|
||||
<upladmin-option-card
|
||||
variant="primary"
|
||||
icon="lucide:Star"
|
||||
label="Disabled"
|
||||
disabled
|
||||
></upladmin-option-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
178
ts_web/elements/upladmin-option-card/upladmin-option-card.ts
Normal file
178
ts_web/elements/upladmin-option-card/upladmin-option-card.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import {
|
||||
DeesElement,
|
||||
property,
|
||||
html,
|
||||
customElement,
|
||||
type TemplateResult,
|
||||
css,
|
||||
cssManager,
|
||||
unsafeCSS,
|
||||
} from '@design.estate/dees-element';
|
||||
import * as sharedStyles from '../../styles/shared.styles.js';
|
||||
import { demoFunc } from './upladmin-option-card.demo.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'upladmin-option-card': UpladminOptionCard;
|
||||
}
|
||||
}
|
||||
|
||||
export type TOptionVariant =
|
||||
// Severity variants
|
||||
| 'critical' | 'major' | 'minor' | 'maintenance'
|
||||
// Status variants
|
||||
| 'investigating' | 'identified' | 'monitoring' | 'resolved' | 'postmortem'
|
||||
// Generic variants
|
||||
| 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
|
||||
|
||||
@customElement('upladmin-option-card')
|
||||
export class UpladminOptionCard extends DeesElement {
|
||||
public static demo = demoFunc;
|
||||
|
||||
@property({ type: String })
|
||||
accessor icon: string = '';
|
||||
|
||||
@property({ type: String })
|
||||
accessor label: string = '';
|
||||
|
||||
@property({ type: String })
|
||||
accessor description: string = '';
|
||||
|
||||
@property({ type: String, reflect: true })
|
||||
accessor variant: TOptionVariant = 'default';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
accessor selected: boolean = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
accessor disabled: boolean = false;
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
font-family: ${unsafeCSS(sharedStyles.fonts.base)};
|
||||
}
|
||||
|
||||
.option-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 18px 14px;
|
||||
background: ${cssManager.bdTheme('#ffffff', '#09090b')};
|
||||
border: 2px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.option-card:hover:not(.disabled) {
|
||||
border-color: ${cssManager.bdTheme('#d4d4d8', '#3f3f46')};
|
||||
background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||
}
|
||||
|
||||
:host([selected]) .option-card {
|
||||
border-color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
|
||||
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.05)', 'rgba(96, 165, 250, 0.1)')};
|
||||
}
|
||||
|
||||
:host([disabled]) .option-card {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.option-label {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||
}
|
||||
|
||||
.option-desc {
|
||||
font-size: 11px;
|
||||
color: ${cssManager.bdTheme('#a1a1aa', '#71717a')};
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* Variant icon colors - all using bdTheme for proper light/dark support */
|
||||
|
||||
/* Severity variants */
|
||||
:host([variant="critical"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#dc2626', '#f87171')};
|
||||
}
|
||||
:host([variant="major"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
|
||||
}
|
||||
:host([variant="minor"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#ca8a04', '#fbbf24')};
|
||||
}
|
||||
:host([variant="maintenance"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
|
||||
}
|
||||
|
||||
/* Status variants */
|
||||
:host([variant="investigating"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
|
||||
}
|
||||
:host([variant="identified"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#ca8a04', '#fbbf24')};
|
||||
}
|
||||
:host([variant="monitoring"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
|
||||
}
|
||||
:host([variant="resolved"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
|
||||
}
|
||||
:host([variant="postmortem"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#9333ea', '#a855f7')};
|
||||
}
|
||||
|
||||
/* Generic variants */
|
||||
:host([variant="default"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||
}
|
||||
:host([variant="primary"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
|
||||
}
|
||||
:host([variant="success"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
|
||||
}
|
||||
:host([variant="warning"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#ca8a04', '#fbbf24')};
|
||||
}
|
||||
:host([variant="danger"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#dc2626', '#f87171')};
|
||||
}
|
||||
:host([variant="info"]) dees-icon {
|
||||
--icon-color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
|
||||
}
|
||||
|
||||
dees-icon {
|
||||
color: var(--icon-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div class="option-card ${this.disabled ? 'disabled' : ''}" @click="${this.handleClick}">
|
||||
${this.icon ? html`<dees-icon .icon=${this.icon} .iconSize=${24}></dees-icon>` : ''}
|
||||
${this.label ? html`<span class="option-label">${this.label}</span>` : ''}
|
||||
${this.description ? html`<span class="option-desc">${this.description}</span>` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private handleClick() {
|
||||
if (this.disabled) return;
|
||||
|
||||
this.dispatchEvent(new CustomEvent('select', {
|
||||
detail: { selected: !this.selected },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user