diff --git a/changelog.md b/changelog.md index 561c293..0fa22a3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2026-04-12 - 3.78.0 - feat(dees-settings) +add dees-settings layout component for displaying read-only settings with footer actions + +- introduces a new dees-settings element with heading, description, settings field grid, and footer action support +- exports dees-settings from the 00group-layout module index +- adds demo examples covering populated, empty, and multi-action states + ## 2026-04-12 - 3.77.0 - feat(dees-table) add configurable cell flash comparison and border highlight mode diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 0277571..69635a2 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@design.estate/dees-catalog', - version: '3.77.0', + version: '3.78.0', description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' } diff --git a/ts_web/elements/00group-layout/dees-settings/dees-settings.demo.ts b/ts_web/elements/00group-layout/dees-settings/dees-settings.demo.ts new file mode 100644 index 0000000..56d5c10 --- /dev/null +++ b/ts_web/elements/00group-layout/dees-settings/dees-settings.demo.ts @@ -0,0 +1,65 @@ +import { html, css, cssManager } from '@design.estate/dees-element'; +import './dees-settings.js'; +import type { ISettingsField, ISettingsAction } from './dees-settings.js'; + +export const demoFunc = () => { + const acmeFields: ISettingsField[] = [ + { key: 'email', label: 'Account email', value: 'admin@example.com' }, + { key: 'status', label: 'Status', value: 'enabled' }, + { key: 'mode', label: 'Mode', value: 'production' }, + { key: 'autoRenew', label: 'Auto-renew', value: 'on' }, + { key: 'threshold', label: 'Renewal threshold', value: '30 days' }, + ]; + + const acmeActions: ISettingsAction[] = [ + { name: 'Edit', action: () => console.log('Edit clicked') }, + ]; + + const emptyActions: ISettingsAction[] = [ + { name: 'Configure', action: () => console.log('Configure clicked') }, + ]; + + const multiActions: ISettingsAction[] = [ + { name: 'Reset', action: () => console.log('Reset clicked') }, + { name: 'Edit', action: () => console.log('Edit clicked') }, + ]; + + return html` + + + + + + + + + + + `; +}; diff --git a/ts_web/elements/00group-layout/dees-settings/dees-settings.ts b/ts_web/elements/00group-layout/dees-settings/dees-settings.ts new file mode 100644 index 0000000..fe6e821 --- /dev/null +++ b/ts_web/elements/00group-layout/dees-settings/dees-settings.ts @@ -0,0 +1,196 @@ +import { + customElement, + DeesElement, + html, + css, + cssManager, + property, + type TemplateResult, +} from '@design.estate/dees-element'; +import { demoFunc } from './dees-settings.demo.js'; +import { cssGeistFontFamily } from '../../00fonts.js'; +import { themeDefaultStyles } from '../../00theme.js'; +import '../../00group-layout/dees-tile/dees-tile.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-settings': DeesSettings; + } +} + +export interface ISettingsField { + key: string; + label: string; + value: string | TemplateResult; +} + +export interface ISettingsAction { + name: string; + action: () => void | Promise; +} + +/** + * dees-settings — a read-only settings display tile with modal-style footer actions. + * + * Renders a dees-tile with a heading, a grid of label/value fields, + * and a footer action bar. When an action is clicked the component + * dispatches a `settings-action` CustomEvent with the action name. + */ +@customElement('dees-settings') +export class DeesSettings extends DeesElement { + public static demo = demoFunc; + public static demoGroups = ['Layout']; + + @property({ type: String }) + accessor heading: string = ''; + + @property({ type: String }) + accessor description: string = ''; + + @property({ attribute: false }) + accessor settingsFields: ISettingsField[] = []; + + @property({ attribute: false }) + accessor actions: ISettingsAction[] = []; + + public static styles = [ + themeDefaultStyles, + cssManager.defaultStyles, + css` + :host { + display: block; + font-family: ${cssGeistFontFamily}; + } + + .settingsGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 12px 24px; + padding: 16px; + } + + .settingsField { + display: flex; + flex-direction: column; + gap: 2px; + } + + .fieldLabel { + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.03em; + color: var(--dees-color-text-muted); + } + + .fieldValue { + font-size: 13px; + color: var(--dees-color-text-primary); + } + + .settingsDescription { + padding: 16px; + font-size: 13px; + line-height: 1.5; + color: var(--dees-color-text-muted); + } + + .bottomButtons { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + gap: 0; + height: 36px; + width: 100%; + box-sizing: border-box; + } + + .bottomButtons .bottomButton { + 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; + } + + .bottomButtons .bottomButton:first-child { + border-left: none; + } + + .bottomButtons .bottomButton:hover { + background: var(--dees-color-hover); + color: var(--dees-color-text-primary); + } + + .bottomButtons .bottomButton:active { + background: ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(0 0% 13%)')}; + } + + .bottomButtons .bottomButton.primary { + color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; + font-weight: 600; + } + + .bottomButtons .bottomButton.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%)')}; + } + + .bottomButtons .bottomButton.primary:active { + background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.15)', 'hsl(213.1 93.9% 67.8% / 0.15)')}; + } + `, + ]; + + public render(): TemplateResult { + const hasFields = this.settingsFields.length > 0; + const hasActions = this.actions.length > 0; + + return html` + + ${hasFields + ? html` + + ${this.settingsFields.map( + (field) => html` + + ${field.label} + ${field.value} + + `, + )} + + ` + : html` + ${this.description} + `} + ${hasActions + ? html` + + ${this.actions.map( + (actionArg, index) => html` + actionArg.action()} + > + ${actionArg.name} + + `, + )} + + ` + : ''} + + `; + } +} diff --git a/ts_web/elements/00group-layout/dees-settings/index.ts b/ts_web/elements/00group-layout/dees-settings/index.ts new file mode 100644 index 0000000..ab1b460 --- /dev/null +++ b/ts_web/elements/00group-layout/dees-settings/index.ts @@ -0,0 +1 @@ +export * from './dees-settings.js'; diff --git a/ts_web/elements/00group-layout/index.ts b/ts_web/elements/00group-layout/index.ts index a61ad17..b5ef84c 100644 --- a/ts_web/elements/00group-layout/index.ts +++ b/ts_web/elements/00group-layout/index.ts @@ -5,5 +5,6 @@ export * from './dees-heading/index.js'; export * from './dees-label/index.js'; export * from './dees-pagination/index.js'; export * from './dees-panel/index.js'; +export * from './dees-settings/index.js'; export * from './dees-stepper/index.js'; export * from './dees-tile/index.js';