diff --git a/changelog.md b/changelog.md index 5ff3b80..bbdaeb9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2026-04-07 - 2.12.0 - feat(elements) +standardize dashboard and detail views on dees tile and stats grid components + +- replace custom stat cards with dees-statsgrid across status and network views and remove the obsolete sz-stat-card element +- migrate multiple detail and settings views to dees-tile headers and footers for consistent action placement and styling +- extend sz-config-section with footer links and actions plus improved collapsed tile behavior + ## 2026-04-05 - 2.11.2 - fix(route-card) align route card with source profile metadata and vpnOnly route configuration diff --git a/readme.hints.md b/readme.hints.md index 7c8f8b1..d8a13f9 100644 --- a/readme.hints.md +++ b/readme.hints.md @@ -2,7 +2,7 @@ ## Project Structure - `html/index.ts` - WccTools setup with sections for Pages and Elements -- `ts_web/elements/` - All web components (34 elements + 9 demo-view wrappers) +- `ts_web/elements/` - All web components (33 elements + 9 demo-view wrappers) - `ts_web/elements/index.ts` - Barrel export for all element components - `ts_web/pages/` - Page components @@ -16,7 +16,7 @@ ## Demo Groups | Group | Elements | |-------|----------| -| Dashboard | sz-dashboard-view, sz-stat-card, sz-resource-usage-card, sz-traffic-card, sz-quick-actions-card | +| Dashboard | sz-dashboard-view, sz-resource-usage-card, sz-traffic-card, sz-quick-actions-card | | Dashboard Grids | sz-status-grid-cluster, sz-status-grid-services, sz-status-grid-network, sz-status-grid-infra | | Platform | sz-platform-services-card, sz-platform-service-detail-view | | Network | sz-network-proxy-view, sz-network-dns-view, sz-network-domains-view, sz-reverse-proxy-card, sz-dns-ssl-card, sz-certificates-card, sz-domain-detail-view | diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 47679ce..2e08f75 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/catalog', - version: '2.11.2', + version: '2.12.0', description: 'UI component catalog for serve.zone' } diff --git a/ts_web/elements/index.ts b/ts_web/elements/index.ts index 911663b..2da4959 100644 --- a/ts_web/elements/index.ts +++ b/ts_web/elements/index.ts @@ -1,5 +1,4 @@ // Dashboard Cards -export * from './sz-stat-card.js'; export * from './sz-resource-usage-card.js'; export * from './sz-traffic-card.js'; export * from './sz-platform-services-card.js'; diff --git a/ts_web/elements/sz-config-section.ts b/ts_web/elements/sz-config-section.ts index ffe257f..89888cf 100644 --- a/ts_web/elements/sz-config-section.ts +++ b/ts_web/elements/sz-config-section.ts @@ -24,6 +24,13 @@ export interface IConfigSectionAction { detail?: any; } +export interface IConfigSectionLink { + label: string; + href: string; + icon?: string; + external?: boolean; +} + declare global { interface HTMLElementTagNameMap { 'sz-config-section': SzConfigSection; @@ -46,6 +53,12 @@ export class SzConfigSection extends DeesElement { { key: 'Auto Renew', value: true, type: 'boolean' }, { key: 'Renew Threshold', value: '30 days' }, ] as IConfigField[]} + .links=${[ + { label: 'Docs', href: 'https://code.foss.global/serve.zone/smartproxy', icon: 'lucide:bookOpen', external: true }, + ] as IConfigSectionLink[]} + .actions=${[ + { label: 'Configure', icon: 'lucide:settings', event: 'configure' }, + ] as IConfigSectionAction[]} > `; @@ -91,6 +114,9 @@ export class SzConfigSection extends DeesElement { @property({ type: Array }) public accessor actions: IConfigSectionAction[] = []; + @property({ type: Array }) + public accessor links: IConfigSectionLink[] = []; + @property({ type: Boolean }) public accessor collapsible: boolean = false; @@ -108,20 +134,25 @@ export class SzConfigSection extends DeesElement { margin-bottom: 16px; } - .section { - background: ${cssManager.bdTheme('#ffffff', '#09090b')}; - border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - border-radius: 8px; - overflow: hidden; + dees-tile { + display: block; + } + + :host([collapsed]) dees-tile::part(content) { + display: none; + } + + :host([collapsed]) dees-tile::part(footer) { + display: none; } .section-header { display: flex; align-items: center; - justify-content: space-between; - padding: 14px 20px; - background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; - border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; + padding: 10px 16px; + gap: 12px; + width: 100%; + box-sizing: border-box; cursor: default; user-select: none; } @@ -131,30 +162,31 @@ export class SzConfigSection extends DeesElement { } :host([collapsible]) .section-header:hover { - background: ${cssManager.bdTheme('#ebebed', '#1c1c1f')}; + background: var(--dees-color-hover); } .header-left { display: flex; align-items: center; - gap: 12px; + gap: 10px; min-width: 0; + flex: 1; } .header-icon { display: flex; align-items: center; justify-content: center; - width: 36px; - height: 36px; - background: ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - border-radius: 8px; + width: 28px; + height: 28px; + background: var(--dees-color-border-default); + border-radius: 6px; flex-shrink: 0; } .header-icon dees-icon { - font-size: 18px; - color: ${cssManager.bdTheme('#52525b', '#a1a1aa')}; + font-size: 14px; + color: var(--dees-color-text-muted); } .header-text { @@ -162,15 +194,17 @@ export class SzConfigSection extends DeesElement { } .header-title { - font-size: 15px; - font-weight: 600; - color: ${cssManager.bdTheme('#18181b', '#fafafa')}; + font-size: 13px; + font-weight: 500; + letter-spacing: -0.01em; + color: var(--dees-color-text-secondary); line-height: 1.3; } .header-subtitle { - font-size: 12px; - color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; + font-size: 11px; + color: var(--dees-color-text-muted); + letter-spacing: -0.01em; line-height: 1.3; margin-top: 1px; } @@ -236,30 +270,60 @@ export class SzConfigSection extends DeesElement { background: ${cssManager.bdTheme('#f59e0b', '#fbbf24')}; } - /* Action buttons */ - .header-action { - display: inline-flex; + /* Footer action buttons — canonical dees-modal / dees-tile pattern */ + .section-footer { + display: flex; + flex-direction: row; + justify-content: flex-end; align-items: center; - gap: 5px; - padding: 4px 12px; - border-radius: 6px; + gap: 0; + height: 36px; + width: 100%; + box-sizing: border-box; + } + + .tile-button { + padding: 0 16px; + height: 100%; + text-align: center; font-size: 12px; font-weight: 500; - color: ${cssManager.bdTheme('#2563eb', '#60a5fa')}; + cursor: pointer; + user-select: none; + transition: all 0.15s ease; background: transparent; border: none; - cursor: pointer; - transition: background 150ms ease; + border-left: 1px solid var(--dees-color-border-subtle); + color: var(--dees-color-text-muted); white-space: nowrap; + display: flex; + align-items: center; + gap: 6px; font-family: inherit; + text-decoration: none; } - .header-action:hover { - background: ${cssManager.bdTheme('rgba(37,99,235,0.08)', 'rgba(96,165,250,0.1)')}; + .tile-button:first-child { + border-left: none; } - .header-action dees-icon { - font-size: 14px; + .tile-button:hover { + background: var(--dees-color-hover); + color: var(--dees-color-text-primary); + } + + .tile-button.primary { + color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; + font-weight: 600; + } + + .tile-button.primary:hover { + background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.08)', 'hsl(213.1 93.9% 67.8% / 0.08)')}; + color: ${cssManager.bdTheme('hsl(217.2 91.2% 50%)', 'hsl(213.1 93.9% 75%)')}; + } + + .tile-button dees-icon { + font-size: 12px; } /* Chevron */ @@ -274,8 +338,8 @@ export class SzConfigSection extends DeesElement { } .chevron dees-icon { - font-size: 16px; - color: ${cssManager.bdTheme('#a1a1aa', '#52525b')}; + font-size: 14px; + color: var(--dees-color-text-muted); } /* Content */ @@ -283,10 +347,6 @@ export class SzConfigSection extends DeesElement { padding: 0; } - .section-content.collapsed { - display: none; - } - /* Field rows */ .field-row { display: flex; @@ -439,6 +499,13 @@ export class SzConfigSection extends DeesElement { } } + updated(changedProperties: Map) { + super.updated(changedProperties); + if (changedProperties.has('isCollapsed')) { + this.toggleAttribute('collapsed', this.isCollapsed); + } + } + public render(): TemplateResult { const statusLabels: Record = { 'enabled': 'Enabled', @@ -448,8 +515,9 @@ export class SzConfigSection extends DeesElement { }; return html` -
+
{ if (this.collapsible) { @@ -475,8 +543,36 @@ export class SzConfigSection extends DeesElement { ${statusLabels[this.status] || this.status} ` : ''} + ${this.collapsible ? html` + + + + ` : ''} +
+
+
+ ${this.fields.map(field => this.renderField(field))} +
+ +
+
+ ${this.links.length > 0 || this.actions.length > 0 ? html` + - -
- ${this.fields.map(field => this.renderField(field))} -
- -
-
- + ` : ''} + `; } diff --git a/ts_web/elements/sz-domain-detail-view.ts b/ts_web/elements/sz-domain-detail-view.ts index bdb8562..c24a37b 100644 --- a/ts_web/elements/sz-domain-detail-view.ts +++ b/ts_web/elements/sz-domain-detail-view.ts @@ -229,57 +229,87 @@ export class SzDomainDetailView extends DeesElement { } } - .section { - background: ${cssManager.bdTheme('#ffffff', '#09090b')}; - border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - border-radius: 8px; - overflow: hidden; - } - - .section.full-width { + dees-tile.full-width { grid-column: 1 / -1; } .section-header { + height: 36px; display: flex; - justify-content: space-between; align-items: center; - padding: 14px 16px; - border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; + padding: 0 16px; + width: 100%; + box-sizing: border-box; } .section-title { - font-size: 14px; - font-weight: 600; - color: ${cssManager.bdTheme('#18181b', '#fafafa')}; + flex: 1; display: flex; align-items: center; gap: 8px; + font-weight: 500; + font-size: 13px; + letter-spacing: -0.01em; + color: var(--dees-color-text-secondary); } .section-title svg { - width: 16px; - height: 16px; - color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; + width: 14px; + height: 14px; + flex-shrink: 0; + color: var(--dees-color-text-secondary); } - .section-action { - padding: 6px 10px; - background: transparent; - border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - border-radius: 4px; + .section-footer { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + gap: 0; + height: 36px; + width: 100%; + box-sizing: border-box; + } + + .tile-button { + padding: 0 16px; + height: 100%; + text-align: center; font-size: 12px; - color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; + font-weight: 500; cursor: pointer; - transition: all 200ms ease; + user-select: none; + transition: all 0.15s ease; + background: transparent; + border: none; + border-left: 1px solid var(--dees-color-border-subtle); + color: var(--dees-color-text-muted); + white-space: nowrap; + display: flex; + align-items: center; + gap: 6px; } - .section-action:hover { - background: ${cssManager.bdTheme('#ffffff', '#09090b')}; - color: ${cssManager.bdTheme('#18181b', '#fafafa')}; + .tile-button:first-child { + border-left: none; } + .tile-button:hover { + background: var(--dees-color-hover); + color: var(--dees-color-text-primary); + } + + .tile-button.primary { + color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; + font-weight: 600; + } + + .tile-button.primary:hover { + background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.08)', 'hsl(213.1 93.9% 67.8% / 0.08)')}; + color: ${cssManager.bdTheme('hsl(217.2 91.2% 50%)', 'hsl(213.1 93.9% 75%)')}; + } + + .section-content { padding: 16px; } @@ -582,8 +612,8 @@ export class SzDomainDetailView extends DeesElement {
-
-
+ +
@@ -591,9 +621,6 @@ export class SzDomainDetailView extends DeesElement { SSL Certificate
- ${this.certificate ? html` - - ` : ''}
${this.certificate ? html` @@ -652,11 +679,16 @@ export class SzDomainDetailView extends DeesElement {
No certificate configured
`}
-
+ ${this.certificate ? html` + + ` : ''} + -
-
+ +
@@ -679,11 +711,11 @@ export class SzDomainDetailView extends DeesElement {
No proxy routes configured
`}
-
+
-
-
+ +
@@ -692,13 +724,6 @@ export class SzDomainDetailView extends DeesElement { DNS Records
-
${this.dnsRecords.length > 0 ? html` @@ -737,7 +762,16 @@ export class SzDomainDetailView extends DeesElement {
No DNS records configured
`}
-
+ +
`; } diff --git a/ts_web/elements/sz-mta-detail-view.ts b/ts_web/elements/sz-mta-detail-view.ts index 9c2f3b3..cafadea 100644 --- a/ts_web/elements/sz-mta-detail-view.ts +++ b/ts_web/elements/sz-mta-detail-view.ts @@ -256,31 +256,89 @@ export class SzMtaDetailView extends DeesElement { gap: 24px; } - .card { - background: ${cssManager.bdTheme('#ffffff', '#09090b')}; - border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - border-radius: 8px; - overflow: hidden; + .card-header { + height: 36px; + display: flex; + align-items: center; + padding: 0 16px; + width: 100%; + box-sizing: border-box; } - .card-header { + .card-heading { + flex: 1; display: flex; - justify-content: space-between; - align-items: center; - padding: 16px; - border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; + align-items: baseline; + gap: 8px; + min-width: 0; } .card-title { - font-size: 16px; - font-weight: 600; - color: ${cssManager.bdTheme('#18181b', '#fafafa')}; + font-weight: 500; + font-size: 13px; + letter-spacing: -0.01em; + color: var(--dees-color-text-secondary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .card-subtitle { - font-size: 13px; - color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; - margin-top: 2px; + font-size: 12px; + color: var(--dees-color-text-muted); + letter-spacing: -0.01em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .card-footer { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + gap: 0; + height: 36px; + width: 100%; + box-sizing: border-box; + } + + .tile-button { + padding: 0 16px; + height: 100%; + text-align: center; + font-size: 12px; + font-weight: 500; + cursor: pointer; + user-select: none; + transition: all 0.15s ease; + background: transparent; + border: none; + border-left: 1px solid var(--dees-color-border-subtle); + color: var(--dees-color-text-muted); + white-space: nowrap; + display: flex; + align-items: center; + gap: 6px; + } + + .tile-button:first-child { + border-left: none; + } + + .tile-button:hover { + background: var(--dees-color-hover); + color: var(--dees-color-text-primary); + } + + .tile-button.primary { + color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; + font-weight: 600; + } + + .tile-button.primary:hover { + background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.08)', 'hsl(213.1 93.9% 67.8% / 0.08)')}; + color: ${cssManager.bdTheme('hsl(217.2 91.2% 50%)', 'hsl(213.1 93.9% 75%)')}; } .card-content { @@ -451,37 +509,13 @@ export class SzMtaDetailView extends DeesElement { color: ${cssManager.bdTheme('#dc2626', '#ef4444')}; } - /* Copy button */ - .smtp-copy-button { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - border-radius: 6px; - border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; - background: transparent; - color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; - font-size: 12px; - font-weight: 500; - cursor: pointer; - transition: all 150ms ease; - } - - .smtp-copy-button:hover { - background: ${cssManager.bdTheme('#f4f4f5', '#27272a')}; - color: ${cssManager.bdTheme('#18181b', '#fafafa')}; - border-color: ${cssManager.bdTheme('#d4d4d8', '#3f3f46')}; - } - - /* Header subtitle enhancements */ + /* SMTP metadata banner — sits inside content, above the log */ .smtp-header-subtitle { - font-size: 13px; - color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; - margin-top: 2px; - display: flex; - align-items: center; - gap: 8px; - flex-wrap: wrap; + padding: 10px 16px; + font-size: 12px; + color: var(--dees-color-text-muted); + border-bottom: 1px solid var(--dees-color-border-subtle); + font-family: monospace; } .smtp-direction-badge { @@ -578,7 +612,7 @@ export class SzMtaDetailView extends DeesElement { color: ${cssManager.bdTheme('#ca8a04', '#facc15')}; } - .rejection-card { + dees-tile.rejection-card::part(outer) { border-color: ${cssManager.bdTheme('#fecaca', 'rgba(239, 68, 68, 0.3)')}; } @@ -646,9 +680,11 @@ export class SzMtaDetailView extends DeesElement {
-
-
-
Email Metadata
+ +
+
+ Email Metadata +
@@ -684,49 +720,53 @@ export class SzMtaDetailView extends DeesElement {
-
+ -
-
-
-
SMTP Transaction Log
-
- ${email.direction} - ${email.direction === 'outbound' - ? `${email.connectionInfo.sourceHostname} → ${email.connectionInfo.destinationIp}:${email.connectionInfo.destinationPort}` - : `${email.connectionInfo.sourceIp} → ${email.connectionInfo.sourceHostname}:${email.connectionInfo.destinationPort}` - } -
+ +
+
+ SMTP Transaction Log + ${email.direction}
-
+
+ ${email.direction === 'outbound' + ? `${email.connectionInfo.sourceHostname} → ${email.connectionInfo.destinationIp}:${email.connectionInfo.destinationPort}` + : `${email.connectionInfo.sourceIp} → ${email.connectionInfo.sourceHostname}:${email.connectionInfo.destinationPort}` + } +
+ ${this.renderSmtpLog(email)} + - ${this.renderSmtpLog(email)} -
+ -
-
-
-
Email Body (Escaped)
-
Raw content — HTML is not rendered
+ +
+
+ Email Body (Escaped) + Raw content — HTML is not rendered
-
+