diff --git a/changelog.md b/changelog.md
index 556c411..4c583b8 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,13 @@
# Changelog
+## 2026-02-23 - 2.4.0 - feat(elements)
+add configuration overview and section components with demo view and index exports
+
+- Adds new sz-config-section component (IConfigField interface, rich renderers for boolean, pills, badge, code, link and 'Not configured' handling).
+- Adds new sz-config-overview wrapper component with heading/info banner and slot styling.
+- Adds demo view sz-demo-view-config that supplies example configuration groups and fields for System, Proxy, Email, DNS, TLS, Cache, RADIUS and Remote Ingress.
+- Exports new components from ts_web/elements/index.ts so they are available to the element registry.
+
## 2026-02-22 - 2.3.0 - feat(routes)
add route UI components and demo view with list/card and app-shell integration
diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts
index 44fe2ea..2914cfd 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.3.0',
+ version: '2.4.0',
description: 'UI component catalog for serve.zone'
}
diff --git a/ts_web/elements/index.ts b/ts_web/elements/index.ts
index a4bbd85..b373504 100644
--- a/ts_web/elements/index.ts
+++ b/ts_web/elements/index.ts
@@ -53,6 +53,10 @@ export * from './sz-mta-detail-view.js';
export * from './sz-route-card.js';
export * from './sz-route-list-view.js';
+// Config Views
+export * from './sz-config-section.js';
+export * from './sz-config-overview.js';
+
// Demo Views
export * from './sz-demo-view-dashboard.js';
export * from './sz-demo-view-services.js';
@@ -62,3 +66,4 @@ export * from './sz-demo-view-tokens.js';
export * from './sz-demo-view-settings.js';
export * from './sz-demo-view-mta.js';
export * from './sz-demo-view-routes.js';
+export * from './sz-demo-view-config.js';
diff --git a/ts_web/elements/sz-config-overview.ts b/ts_web/elements/sz-config-overview.ts
new file mode 100644
index 0000000..c30a4ee
--- /dev/null
+++ b/ts_web/elements/sz-config-overview.ts
@@ -0,0 +1,92 @@
+import {
+ DeesElement,
+ customElement,
+ html,
+ css,
+ cssManager,
+ property,
+ type TemplateResult,
+} from '@design.estate/dees-element';
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'sz-config-overview': SzConfigOverview;
+ }
+}
+
+@customElement('sz-config-overview')
+export class SzConfigOverview extends DeesElement {
+ public static demo = () => html`
+
+ Place <sz-config-section> elements here
+
+ `;
+
+ public static demoGroups = ['Configuration'];
+
+ @property({ type: String })
+ public accessor heading: string = '';
+
+ @property({ type: String })
+ public accessor infoText: string = '';
+
+ public static styles = [
+ cssManager.defaultStyles,
+ css`
+ :host {
+ display: block;
+ }
+
+ .heading {
+ font-size: 20px;
+ font-weight: 600;
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
+ margin-bottom: 16px;
+ }
+
+ .info-banner {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ padding: 14px 18px;
+ margin-bottom: 20px;
+ border-radius: 8px;
+ background: ${cssManager.bdTheme('#eff6ff', 'rgba(59,130,246,0.08)')};
+ border: 1px solid ${cssManager.bdTheme('#bfdbfe', 'rgba(59,130,246,0.2)')};
+ color: ${cssManager.bdTheme('#1e40af', '#93c5fd')};
+ font-size: 13px;
+ line-height: 1.5;
+ }
+
+ .info-banner dees-icon {
+ flex-shrink: 0;
+ font-size: 18px;
+ margin-top: 1px;
+ }
+
+ ::slotted(sz-config-section) {
+ margin-bottom: 12px;
+ }
+
+ ::slotted(sz-config-section:last-child) {
+ margin-bottom: 0;
+ }
+ `,
+ ];
+
+ public render(): TemplateResult {
+ return html`
+ ${this.heading ? html`
${this.heading}
` : ''}
+ ${this.infoText ? html`
+
+
+ ${this.infoText}
+
+ ` : ''}
+
+ `;
+ }
+}
diff --git a/ts_web/elements/sz-config-section.ts b/ts_web/elements/sz-config-section.ts
new file mode 100644
index 0000000..9f4e6c2
--- /dev/null
+++ b/ts_web/elements/sz-config-section.ts
@@ -0,0 +1,531 @@
+import {
+ DeesElement,
+ customElement,
+ html,
+ css,
+ cssManager,
+ property,
+ state,
+ type TemplateResult,
+} from '@design.estate/dees-element';
+
+export interface IConfigField {
+ key: string;
+ value: string | number | boolean | string[] | null;
+ type?: 'text' | 'boolean' | 'badge' | 'pills' | 'code' | 'link';
+ description?: string;
+ linkTo?: string;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'sz-config-section': SzConfigSection;
+ }
+}
+
+@customElement('sz-config-section')
+export class SzConfigSection extends DeesElement {
+ public static demo = () => html`
+
+
+
+ `;
+
+ public static demoGroups = ['Configuration'];
+
+ @property({ type: String })
+ public accessor title: string = '';
+
+ @property({ type: String })
+ public accessor subtitle: string = '';
+
+ @property({ type: String })
+ public accessor icon: string = '';
+
+ @property({ type: String })
+ public accessor status: 'enabled' | 'disabled' | 'not-configured' | 'warning' = 'enabled';
+
+ @property({ type: Array })
+ public accessor fields: IConfigField[] = [];
+
+ @property({ type: Boolean })
+ public accessor collapsible: boolean = false;
+
+ @property({ type: Boolean })
+ public accessor collapsed: boolean = false;
+
+ @state()
+ accessor isCollapsed: boolean = false;
+
+ public static styles = [
+ cssManager.defaultStyles,
+ css`
+ :host {
+ display: block;
+ margin-bottom: 16px;
+ }
+
+ .section {
+ background: ${cssManager.bdTheme('#ffffff', '#09090b')};
+ border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ .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')};
+ cursor: default;
+ user-select: none;
+ }
+
+ :host([collapsible]) .section-header {
+ cursor: pointer;
+ }
+
+ :host([collapsible]) .section-header:hover {
+ background: ${cssManager.bdTheme('#ebebed', '#1c1c1f')};
+ }
+
+ .header-left {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-width: 0;
+ }
+
+ .header-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 36px;
+ height: 36px;
+ background: ${cssManager.bdTheme('#e4e4e7', '#27272a')};
+ border-radius: 8px;
+ flex-shrink: 0;
+ }
+
+ .header-icon dees-icon {
+ font-size: 18px;
+ color: ${cssManager.bdTheme('#52525b', '#a1a1aa')};
+ }
+
+ .header-text {
+ min-width: 0;
+ }
+
+ .header-title {
+ font-size: 15px;
+ font-weight: 600;
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
+ line-height: 1.3;
+ }
+
+ .header-subtitle {
+ font-size: 12px;
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
+ line-height: 1.3;
+ margin-top: 1px;
+ }
+
+ .header-right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex-shrink: 0;
+ }
+
+ /* Status badge */
+ .status-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 3px 10px;
+ border-radius: 9999px;
+ font-size: 12px;
+ font-weight: 500;
+ white-space: nowrap;
+ }
+
+ .status-badge.enabled {
+ background: ${cssManager.bdTheme('#dcfce7', 'rgba(34,197,94,0.2)')};
+ color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
+ }
+
+ .status-badge.disabled {
+ background: ${cssManager.bdTheme('#fee2e2', 'rgba(239,68,68,0.2)')};
+ color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ }
+
+ .status-badge.not-configured {
+ background: ${cssManager.bdTheme('#f4f4f5', 'rgba(113,113,122,0.2)')};
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
+ }
+
+ .status-badge.warning {
+ background: ${cssManager.bdTheme('#fef3c7', 'rgba(245,158,11,0.15)')};
+ color: ${cssManager.bdTheme('#92400e', '#fbbf24')};
+ }
+
+ .status-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ }
+
+ .status-badge.enabled .status-dot {
+ background: ${cssManager.bdTheme('#16a34a', '#22c55e')};
+ }
+
+ .status-badge.disabled .status-dot {
+ background: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ }
+
+ .status-badge.not-configured .status-dot {
+ background: ${cssManager.bdTheme('#a1a1aa', '#52525b')};
+ }
+
+ .status-badge.warning .status-dot {
+ background: ${cssManager.bdTheme('#f59e0b', '#fbbf24')};
+ }
+
+ /* Chevron */
+ .chevron {
+ display: flex;
+ align-items: center;
+ transition: transform 200ms ease;
+ }
+
+ .chevron.collapsed {
+ transform: rotate(-90deg);
+ }
+
+ .chevron dees-icon {
+ font-size: 16px;
+ color: ${cssManager.bdTheme('#a1a1aa', '#52525b')};
+ }
+
+ /* Content */
+ .section-content {
+ padding: 0;
+ }
+
+ .section-content.collapsed {
+ display: none;
+ }
+
+ /* Field rows */
+ .field-row {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ padding: 10px 20px;
+ border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#1a1a1e')};
+ gap: 16px;
+ }
+
+ .field-row:last-child {
+ border-bottom: none;
+ }
+
+ .field-key {
+ font-size: 13px;
+ font-weight: 500;
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
+ flex-shrink: 0;
+ min-width: 140px;
+ padding-top: 1px;
+ }
+
+ .field-value {
+ font-size: 13px;
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
+ text-align: right;
+ word-break: break-all;
+ }
+
+ .field-value.null-value {
+ color: ${cssManager.bdTheme('#a1a1aa', '#52525b')};
+ font-style: italic;
+ font-family: inherit;
+ }
+
+ /* Boolean display */
+ .bool-value {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ font-family: inherit;
+ font-size: 13px;
+ font-weight: 500;
+ }
+
+ .bool-value.true {
+ color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
+ }
+
+ .bool-value.false {
+ color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ }
+
+ .bool-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ }
+
+ .bool-value.true .bool-dot {
+ background: ${cssManager.bdTheme('#16a34a', '#22c55e')};
+ }
+
+ .bool-value.false .bool-dot {
+ background: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ }
+
+ /* Pills */
+ .pills {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 5px;
+ justify-content: flex-end;
+ }
+
+ .pill {
+ display: inline-flex;
+ align-items: center;
+ padding: 2px 9px;
+ border-radius: 9999px;
+ font-size: 12px;
+ font-weight: 500;
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
+ background: ${cssManager.bdTheme('#eff6ff', 'rgba(59,130,246,0.1)')};
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
+ }
+
+ /* Code value */
+ .code-value {
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
+ font-size: 12px;
+ background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
+ padding: 2px 8px;
+ border-radius: 4px;
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
+ }
+
+ /* Link value */
+ .link-value {
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
+ cursor: pointer;
+ text-decoration: none;
+ font-family: inherit;
+ font-size: 13px;
+ }
+
+ .link-value:hover {
+ text-decoration: underline;
+ }
+
+ /* Description hint */
+ .field-description {
+ font-size: 11px;
+ color: ${cssManager.bdTheme('#a1a1aa', '#52525b')};
+ margin-top: 3px;
+ text-align: right;
+ }
+
+ /* Slot for custom content */
+ .slot-content {
+ border-top: 1px solid ${cssManager.bdTheme('#f4f4f5', '#1a1a1e')};
+ }
+
+ .slot-content:empty {
+ display: none;
+ border-top: none;
+ }
+
+ /* Badge type */
+ .badge-value {
+ display: inline-flex;
+ align-items: center;
+ padding: 2px 9px;
+ border-radius: 9999px;
+ font-size: 12px;
+ font-weight: 500;
+ background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
+ color: ${cssManager.bdTheme('#52525b', '#a1a1aa')};
+ }
+ `,
+ ];
+
+ async connectedCallback() {
+ await super.connectedCallback();
+ this.isCollapsed = this.collapsed;
+ if (this.collapsible) {
+ this.setAttribute('collapsible', '');
+ }
+ }
+
+ public render(): TemplateResult {
+ const statusLabels: Record = {
+ 'enabled': 'Enabled',
+ 'disabled': 'Disabled',
+ 'not-configured': 'Not Configured',
+ 'warning': 'Warning',
+ };
+
+ return html`
+
+
+
+ ${this.fields.map(field => this.renderField(field))}
+
+
+
+
+
+ `;
+ }
+
+ private renderField(field: IConfigField): TemplateResult {
+ return html`
+
+
${field.key}
+
+ ${this.renderFieldValue(field)}
+ ${field.description ? html`
${field.description}
` : ''}
+
+
+ `;
+ }
+
+ private renderFieldValue(field: IConfigField): TemplateResult {
+ const value = field.value;
+ const type = field.type || this.inferType(value);
+
+ // Null / undefined
+ if (value === null || value === undefined) {
+ return html`Not configured`;
+ }
+
+ switch (type) {
+ case 'boolean':
+ return html`
+
+
+ ${value ? 'Enabled' : 'Disabled'}
+
+ `;
+
+ case 'pills':
+ if (Array.isArray(value) && value.length === 0) {
+ return html`None`;
+ }
+ return html`
+
+ ${(value as string[]).map(v => html`${v}`)}
+
+ `;
+
+ case 'code':
+ return html`${String(value)}`;
+
+ case 'badge':
+ return html`${String(value)}`;
+
+ case 'link':
+ return html`
+ {
+ if (field.linkTo) {
+ this.dispatchEvent(new CustomEvent('navigate', {
+ detail: { target: field.linkTo },
+ bubbles: true,
+ composed: true,
+ }));
+ }
+ }}
+ >${String(value)}
+ `;
+
+ default:
+ return html`${String(value)}`;
+ }
+ }
+
+ private inferType(value: unknown): string {
+ if (typeof value === 'boolean') return 'boolean';
+ if (Array.isArray(value)) return 'pills';
+ return 'text';
+ }
+}
diff --git a/ts_web/elements/sz-demo-view-config.ts b/ts_web/elements/sz-demo-view-config.ts
new file mode 100644
index 0000000..b327f9d
--- /dev/null
+++ b/ts_web/elements/sz-demo-view-config.ts
@@ -0,0 +1,164 @@
+import {
+ DeesElement,
+ customElement,
+ html,
+ css,
+ cssManager,
+ type TemplateResult,
+} from '@design.estate/dees-element';
+import type { IConfigField } from './sz-config-section.js';
+import './index.js';
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'sz-demo-view-config': SzDemoViewConfig;
+ }
+}
+
+@customElement('sz-demo-view-config')
+export class SzDemoViewConfig extends DeesElement {
+ public static styles = [
+ cssManager.defaultStyles,
+ css`
+ :host {
+ display: block;
+ padding: 24px;
+ height: 100%;
+ overflow-y: auto;
+ box-sizing: border-box;
+ }
+ `,
+ ];
+
+ public render(): TemplateResult {
+ const systemFields: IConfigField[] = [
+ { key: 'Base Directory', value: '/home/user/.serve.zone/dcrouter' },
+ { key: 'Data Directory', value: '/home/user/.serve.zone/dcrouter/data' },
+ { key: 'Public IP', value: '203.0.113.50' },
+ { key: 'Proxy IPs', value: ['203.0.113.10', '203.0.113.11'], type: 'pills' },
+ { key: 'Uptime', value: '3d 14h 22m' },
+ { key: 'Storage Backend', value: 'filesystem', type: 'badge' },
+ ];
+
+ const proxyFields: IConfigField[] = [
+ { key: 'Route Count', value: 12 },
+ { key: 'ACME Enabled', value: true, type: 'boolean' },
+ { key: 'Account Email', value: 'admin@serve.zone' },
+ { key: 'Use Production', value: true, type: 'boolean' },
+ { key: 'Auto Renew', value: true, type: 'boolean' },
+ { key: 'Renew Threshold', value: '30 days' },
+ ];
+
+ const emailFields: IConfigField[] = [
+ { key: 'Ports', value: ['25', '465', '587'], type: 'pills' },
+ { key: 'Hostname', value: 'mail.serve.zone' },
+ { key: 'Domains', value: ['serve.zone', 'mail.serve.zone'], type: 'pills' },
+ { key: 'Email Routes', value: 5 },
+ { key: 'Received Path', value: '/data/emails' },
+ ];
+
+ const dnsFields: IConfigField[] = [
+ { key: 'Port', value: 53 },
+ { key: 'NS Domains', value: ['ns1.serve.zone', 'ns2.serve.zone'], type: 'pills' },
+ { key: 'Scopes', value: ['serve.zone', 'example.com'], type: 'pills' },
+ { key: 'Record Count', value: 24 },
+ { key: 'DNS Challenge', value: true, type: 'boolean' },
+ ];
+
+ const tlsFields: IConfigField[] = [
+ { key: 'Contact Email', value: 'admin@serve.zone' },
+ { key: 'Domain', value: 'serve.zone' },
+ { key: 'Source', value: 'acme', type: 'badge' },
+ { key: 'Certificate Path', value: null },
+ { key: 'Key Path', value: null },
+ ];
+
+ const cacheFields: IConfigField[] = [
+ { key: 'Storage Path', value: '/home/user/.serve.zone/dcrouter/tsmdb' },
+ { key: 'DB Name', value: 'dcrouter' },
+ { key: 'Default TTL', value: '30 days' },
+ { key: 'Cleanup Interval', value: '1 hour' },
+ ];
+
+ const radiusFields: IConfigField[] = [
+ { key: 'Auth Port', value: null },
+ { key: 'Accounting Port', value: null },
+ ];
+
+ const remoteIngressFields: IConfigField[] = [
+ { key: 'Tunnel Port', value: 8443 },
+ { key: 'Hub Domain', value: 'hub.serve.zone' },
+ { key: 'TLS Configured', value: true, type: 'boolean' },
+ ];
+
+ return html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+}