update
This commit is contained in:
@ -40,6 +40,89 @@ export const demoFunc = () => html`
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="demo-container">
|
<div class="demo-container">
|
||||||
|
<div class="demo-section">
|
||||||
|
<h3>Header Buttons</h3>
|
||||||
|
<p>Modals can have optional header buttons for help and closing.</p>
|
||||||
|
<div class="button-grid">
|
||||||
|
<dees-button @click=${() => {
|
||||||
|
DeesModal.createAndShow({
|
||||||
|
heading: 'With Help Button',
|
||||||
|
showHelpButton: true,
|
||||||
|
onHelp: async () => {
|
||||||
|
const helpModal = await DeesModal.createAndShow({
|
||||||
|
heading: 'Help',
|
||||||
|
width: 'small',
|
||||||
|
showCloseButton: true,
|
||||||
|
showHelpButton: false,
|
||||||
|
content: html`
|
||||||
|
<p>This is the help content for the modal.</p>
|
||||||
|
<p>You can provide context-specific help here.</p>
|
||||||
|
`,
|
||||||
|
menuOptions: [{
|
||||||
|
name: 'Got it',
|
||||||
|
action: async (modal) => modal.destroy()
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
content: html`
|
||||||
|
<p>This modal has a help button in the header. Click it to see help content.</p>
|
||||||
|
<p>The close button is also visible by default.</p>
|
||||||
|
`,
|
||||||
|
menuOptions: [{
|
||||||
|
name: 'OK',
|
||||||
|
action: async (modal) => modal.destroy()
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}}>With Help Button</dees-button>
|
||||||
|
|
||||||
|
<dees-button @click=${() => {
|
||||||
|
DeesModal.createAndShow({
|
||||||
|
heading: 'No Close Button',
|
||||||
|
showCloseButton: false,
|
||||||
|
content: html`
|
||||||
|
<p>This modal has no close button in the header.</p>
|
||||||
|
<p>You must use the action buttons or click outside to close it.</p>
|
||||||
|
`,
|
||||||
|
menuOptions: [{
|
||||||
|
name: 'Close',
|
||||||
|
action: async (modal) => modal.destroy()
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}}>No Close Button</dees-button>
|
||||||
|
|
||||||
|
<dees-button @click=${() => {
|
||||||
|
DeesModal.createAndShow({
|
||||||
|
heading: 'Both Buttons',
|
||||||
|
showHelpButton: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
onHelp: () => alert('Help clicked!'),
|
||||||
|
content: html`
|
||||||
|
<p>This modal has both help and close buttons.</p>
|
||||||
|
`,
|
||||||
|
menuOptions: [{
|
||||||
|
name: 'Done',
|
||||||
|
action: async (modal) => modal.destroy()
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}}>Both Buttons</dees-button>
|
||||||
|
|
||||||
|
<dees-button @click=${() => {
|
||||||
|
DeesModal.createAndShow({
|
||||||
|
heading: 'Clean Header',
|
||||||
|
showCloseButton: false,
|
||||||
|
showHelpButton: false,
|
||||||
|
content: html`
|
||||||
|
<p>This modal has a clean header with no buttons.</p>
|
||||||
|
`,
|
||||||
|
menuOptions: [{
|
||||||
|
name: 'Close',
|
||||||
|
action: async (modal) => modal.destroy()
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}}>Clean Header</dees-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="demo-section">
|
<div class="demo-section">
|
||||||
<h3>Modal Width Variations</h3>
|
<h3>Modal Width Variations</h3>
|
||||||
<p>Modals can have different widths: small, medium, large, fullscreen, or custom pixel values.</p>
|
<p>Modals can have different widths: small, medium, large, fullscreen, or custom pixel values.</p>
|
||||||
@ -108,18 +191,25 @@ export const demoFunc = () => html`
|
|||||||
|
|
||||||
<dees-button @click=${() => {
|
<dees-button @click=${() => {
|
||||||
DeesModal.createAndShow({
|
DeesModal.createAndShow({
|
||||||
heading: 'Fullscreen Modal',
|
heading: 'Fullscreen Editor',
|
||||||
width: 'fullscreen',
|
width: 'fullscreen',
|
||||||
|
showHelpButton: true,
|
||||||
|
onHelp: async () => {
|
||||||
|
alert('In a real app, this would show editor documentation');
|
||||||
|
},
|
||||||
content: html`
|
content: html`
|
||||||
<h4>Fullscreen Experience</h4>
|
<h4>Fullscreen Experience with Header Controls</h4>
|
||||||
<p>This modal takes up almost the entire viewport with a 20px margin on all sides. Great for immersive experiences, detailed editors, or when you need maximum space.</p>
|
<p>This modal takes up almost the entire viewport with a 20px margin on all sides. The header buttons are particularly useful in fullscreen mode.</p>
|
||||||
<p>The content area can be as tall as needed and will scroll if necessary.</p>
|
<p>The content area can be as tall as needed and will scroll if necessary.</p>
|
||||||
<div style="height: 200px; background: ${cssManager.bdTheme('#f0f0f0', '#2a2a2a')}; border-radius: 8px; display: flex; align-items: center; justify-content: center; margin-top: 16px;">
|
<div style="height: 200px; background: ${cssManager.bdTheme('#f0f0f0', '#2a2a2a')}; border-radius: 8px; display: flex; align-items: center; justify-content: center; margin-top: 16px;">
|
||||||
<span style="color: ${cssManager.bdTheme('#999', '#666')}">Large content area</span>
|
<span style="color: ${cssManager.bdTheme('#999', '#666')}">Large content area</span>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
menuOptions: [{
|
menuOptions: [{
|
||||||
name: 'Close',
|
name: 'Save',
|
||||||
|
action: async (modal) => modal.destroy()
|
||||||
|
}, {
|
||||||
|
name: 'Cancel',
|
||||||
action: async (modal) => modal.destroy()
|
action: async (modal) => modal.destroy()
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
@ -217,7 +307,7 @@ export const demoFunc = () => html`
|
|||||||
DeesModal.createAndShow({
|
DeesModal.createAndShow({
|
||||||
heading: 'No Actions',
|
heading: 'No Actions',
|
||||||
content: html`
|
content: html`
|
||||||
<p>This modal has no buttons. Click outside or press ESC to close.</p>
|
<p>This modal has no bottom buttons. Use the X button or click outside to close.</p>
|
||||||
<p style="margin-top: 16px; color: ${cssManager.bdTheme('#666', '#999')};">This is useful for informational modals that don't require user action.</p>
|
<p style="margin-top: 16px; color: ${cssManager.bdTheme('#666', '#999')};">This is useful for informational modals that don't require user action.</p>
|
||||||
`,
|
`,
|
||||||
menuOptions: [],
|
menuOptions: [],
|
||||||
@ -249,8 +339,11 @@ export const demoFunc = () => html`
|
|||||||
DeesModal.createAndShow({
|
DeesModal.createAndShow({
|
||||||
heading: 'Responsive Modal',
|
heading: 'Responsive Modal',
|
||||||
width: 'large',
|
width: 'large',
|
||||||
|
showHelpButton: true,
|
||||||
|
onHelp: () => console.log('Help requested for responsive modal'),
|
||||||
content: html`
|
content: html`
|
||||||
<p>Resize your browser window to see how this modal adapts. On mobile viewports, it will automatically take the full width minus margins.</p>
|
<p>Resize your browser window to see how this modal adapts. On mobile viewports, it will automatically take the full width minus margins.</p>
|
||||||
|
<p>The header buttons remain accessible at all viewport sizes.</p>
|
||||||
`,
|
`,
|
||||||
menuOptions: [{
|
menuOptions: [{
|
||||||
name: 'Close',
|
name: 'Close',
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
|
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
import { DeesWindowLayer } from './dees-windowlayer.js';
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
import './dees-icon.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -38,6 +39,9 @@ export class DeesModal extends DeesElement {
|
|||||||
width?: 'small' | 'medium' | 'large' | 'fullscreen' | number;
|
width?: 'small' | 'medium' | 'large' | 'fullscreen' | number;
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
minWidth?: number;
|
minWidth?: number;
|
||||||
|
showCloseButton?: boolean;
|
||||||
|
showHelpButton?: boolean;
|
||||||
|
onHelp?: () => void | Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
const modal = new DeesModal();
|
const modal = new DeesModal();
|
||||||
@ -47,6 +51,9 @@ export class DeesModal extends DeesElement {
|
|||||||
if (optionsArg.width) modal.width = optionsArg.width;
|
if (optionsArg.width) modal.width = optionsArg.width;
|
||||||
if (optionsArg.maxWidth) modal.maxWidth = optionsArg.maxWidth;
|
if (optionsArg.maxWidth) modal.maxWidth = optionsArg.maxWidth;
|
||||||
if (optionsArg.minWidth) modal.minWidth = optionsArg.minWidth;
|
if (optionsArg.minWidth) modal.minWidth = optionsArg.minWidth;
|
||||||
|
if (optionsArg.showCloseButton !== undefined) modal.showCloseButton = optionsArg.showCloseButton;
|
||||||
|
if (optionsArg.showHelpButton !== undefined) modal.showHelpButton = optionsArg.showHelpButton;
|
||||||
|
if (optionsArg.onHelp) modal.onHelp = optionsArg.onHelp;
|
||||||
modal.windowLayer = await DeesWindowLayer.createAndShow({
|
modal.windowLayer = await DeesWindowLayer.createAndShow({
|
||||||
blur: true,
|
blur: true,
|
||||||
});
|
});
|
||||||
@ -80,6 +87,15 @@ export class DeesModal extends DeesElement {
|
|||||||
@property({ type: Number })
|
@property({ type: Number })
|
||||||
public minWidth: number;
|
public minWidth: number;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public showCloseButton: boolean = true;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public showHelpButton: boolean = false;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public onHelp: () => void | Promise<void>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -155,13 +171,61 @@ export class DeesModal extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal .heading {
|
.modal .heading {
|
||||||
height: 32px;
|
height: 40px;
|
||||||
font-family: 'Geist Sans', sans-serif;
|
font-family: 'Geist Sans', sans-serif;
|
||||||
line-height: 32px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme('#e0e0e0', '#333')};
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading .header-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading .header-button {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
background: transparent;
|
||||||
|
color: ${cssManager.bdTheme('#666', '#999')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading .header-button:hover {
|
||||||
|
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.08)')};
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading .header-button:active {
|
||||||
|
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.12)', 'rgba(255, 255, 255, 0.12)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading .header-button dees-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading .heading-text {
|
||||||
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 12px;
|
font-size: 14px;
|
||||||
border-bottom: 1px solid ${cssManager.bdTheme('#e0e0e0', '#333')};
|
line-height: 40px;
|
||||||
|
padding: 0 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .content {
|
.modal .content {
|
||||||
@ -229,7 +293,21 @@ export class DeesModal extends DeesElement {
|
|||||||
</style>
|
</style>
|
||||||
<div class="modalContainer" @click=${this.handleOutsideClick}>
|
<div class="modalContainer" @click=${this.handleOutsideClick}>
|
||||||
<div class="modal ${widthClass}">
|
<div class="modal ${widthClass}">
|
||||||
<div class="heading">${this.heading}</div>
|
<div class="heading">
|
||||||
|
<div class="heading-text">${this.heading}</div>
|
||||||
|
<div class="header-buttons">
|
||||||
|
${this.showHelpButton ? html`
|
||||||
|
<div class="header-button" @click=${this.handleHelp} title="Help">
|
||||||
|
<dees-icon .icon=${'lucide:helpCircle'}></dees-icon>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${this.showCloseButton ? html`
|
||||||
|
<div class="header-button" @click=${() => this.destroy()} title="Close">
|
||||||
|
<dees-icon .icon=${'lucide:x'}></dees-icon>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="content">${this.content}</div>
|
<div class="content">${this.content}</div>
|
||||||
${this.menuOptions.length > 0 ? html`
|
${this.menuOptions.length > 0 ? html`
|
||||||
<div class="bottomButtons">
|
<div class="bottomButtons">
|
||||||
@ -272,4 +350,10 @@ export class DeesModal extends DeesElement {
|
|||||||
document.body.removeChild(this);
|
document.body.removeChild(this);
|
||||||
await this.windowLayer.destroy();
|
await this.windowLayer.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async handleHelp() {
|
||||||
|
if (this.onHelp) {
|
||||||
|
await this.onHelp();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user