8.5 KiB
Modal Dialog Implementation Documentation
Overview
This document describes the implementation of two configurable modal dialog systems for the desktop-angular project:
- Angular in-app modal component (already integrated into the UI)
- Electron-native modal window (opens a frameless BrowserWindow as a dialog)
Both allow variable questions, 1-3 buttons with custom labels, and return metadata for the clicked button. The Electron-native dialog additionally supports color customization for background, text, button colors per dialog.
Files Added/Modified
1. New Files Created
src/frontend/src/app/modal.service.ts
Purpose: Core service for managing modal dialogs What it does:
- Defines interfaces for modal configuration (
ModalConfig
,ModalButton
,ModalResult
) - Provides
ModalService
with methods to show/hide modals - Returns promises that resolve with button click results
- Includes convenience methods for common dialog types
Key Features:
show(config: ModalConfig): Promise<ModalResult>
- Main method to show custom modalsshowConfirm(title, message): Promise<boolean>
- Yes/No confirmation dialogshowYesNoCancel(title, message): Promise<'yes'|'no'|'cancel'>
- Three-option dialogshowInfo(title, message): Promise<void>
- Information dialog with OK button
src/frontend/src/app/modal.component.ts
Purpose: Angular component that renders the modal dialog What it does:
- Displays modal overlay and dialog box
- Renders configurable buttons with different styles
- Handles button clicks and communicates with service
- Manages modal visibility through service subscription
Key Features:
- Standalone Angular component
- Reactive to service state changes
- Supports button styling (primary, secondary, danger)
- Overlay click handling (currently disabled)
src/frontend/src/app/modal.component.scss
Purpose: Styling for the modal dialog What it does:
- Creates modal overlay with semi-transparent background
- Styles dialog box with footer-matching colors (#aa1c3a)
- Implements button styles matching the app's footer buttons
- Provides responsive design for mobile devices
Key Features:
- Modal overlay with backdrop
- Dialog box with header, body, and footer sections
- Button styles matching app footer (white background, red text)
- Three button style variants: primary, secondary, danger
- Mobile-responsive design
2. Modified Files
src/frontend/src/app/root.component.ts
Changes Made:
- Added imports for
ModalService
andModalComponent
- Added
ModalComponent
to component imports - Injected
ModalService
in constructor - Added example methods demonstrating modal usage:
showCustomModal()
- Shows 3-button custom dialogshowConfirmDialog()
- Shows Yes/No confirmationshowYesNoCancelDialog()
- Shows Yes/No/Cancel dialogshowInfoDialog()
- Shows information dialog
src/frontend/src/app/root.component.html
Changes Made:
- Added
<app-modal></app-modal>
component to template - Added test buttons in form section to demonstrate modal functionality
- Test buttons include: Custom Modal, Confirm Dialog, Yes/No/Cancel, Info Dialog
3. Electron-Native Modal (Alternative)
To support invoking modals from the Electron main process with fully customizable styling, we added an alternative modal implementation which opens a dedicated BrowserWindow
as a modal dialog.
New Files
src/main/modal.html
- HTML/CSS/JS for a self-contained modal page
- Receives configuration over IPC (
custom-modal:config
) - Renders title, message and up to 3 buttons
- Colors can be customized via CSS variables populated from config:
- background, text, buttonBg, buttonText, secondaryBg, secondaryText
- Each button can define its own inline style overrides via
buttonStyles
map
Changes in src/main/main.js
- Added
openCustomModalWindow(config)
helper to create a modalBrowserWindow
- Loads
modal.html
and sends the configuration after load - Listens for
custom-modal:result
IPC to resolve the clicked button - Exposed IPC handler
dialog:custom
to open the modal from renderer/preload
Changes in src/preload/preload.js
- Exposed
showNativeModal(config)
inwindow.api
viaipcRenderer.invoke('dialog:custom')
Changes in src/frontend/src/app/ipc.service.ts
- Added wrapper method
showNativeModal(config)
to call the Electron-native modal from Angular code
Usage Example (from Angular renderer)
const result = await this.ipc.showNativeModal({
title: 'System Dialog',
message: 'Proceed with operation?',
buttons: [
{ id: 'yes', label: 'Yes', style: 'primary' },
{ id: 'no', label: 'No', style: 'secondary' },
{ id: 'cancel', label: 'Cancel', style: 'danger' }
],
colors: {
background: '#aa1c3a',
text: '#ffffff',
buttonBg: '#ffffff',
buttonText: '#aa1c3a',
secondaryBg: 'rgba(255,255,255,0.1)',
secondaryText: '#ffffff'
},
buttonStyles: {
yes: { bg: '#ffffff', text: '#aa1c3a' },
no: { bg: 'rgba(255,255,255,0.1)', text: '#ffffff' },
cancel: { bg: '#e53935', text: '#fff' }
}
});
// result => { buttonId: 'yes' | 'no' | 'cancel', buttonIndex: number, buttonLabel?: string }
Usage Examples
Basic Custom Modal
const result = await this.modal.show({
title: 'Custom Dialog',
message: 'Choose an option:',
buttons: [
{ id: 'option1', label: 'Option 1', style: 'primary' },
{ id: 'option2', label: 'Option 2', style: 'secondary' },
{ id: 'cancel', label: 'Cancel', style: 'danger' }
]
});
console.log(`Clicked: ${result.buttonLabel} (ID: ${result.buttonId})`);
Confirmation Dialog
const confirmed = await this.modal.showConfirm(
'Delete Item',
'Are you sure you want to delete this item?'
);
if (confirmed) {
// Proceed with deletion
}
Yes/No/Cancel Dialog
const result = await this.modal.showYesNoCancel(
'Save Changes',
'Do you want to save your changes?'
);
switch (result) {
case 'yes': /* Save and continue */ break;
case 'no': /* Continue without saving */ break;
case 'cancel': /* Cancel operation */ break;
}
Information Dialog
await this.modal.showInfo(
'Success',
'Your changes have been saved successfully.'
);
Button Styles
The modal supports three button styles:
- Primary (
style: 'primary'
): White background, red text - matches footer buttons - Secondary (
style: 'secondary'
): Transparent background, white text - Danger (
style: 'danger'
): Red background, white text
Styling Details
Color Scheme
- Background: #aa1c3a (matches footer)
- Text: White (#ffffff)
- Primary Buttons: White background, red text
- Secondary Buttons: Transparent with white text
- Danger Buttons: Red background (#e53935)
Layout
- Modal overlay covers entire screen
- Dialog is centered and responsive
- Maximum width: 500px
- Mobile-friendly with stacked buttons on small screens
Integration Points
Service Integration
The ModalService
is provided at root level, making it available throughout the application:
constructor(private modal: ModalService) {}
Component Integration
The ModalComponent
is imported in the main component and added to the template:
<app-modal></app-modal>
Testing
The implementation includes test buttons in the form section that demonstrate all modal types:
- Custom Modal: Shows 3-button dialog with different styles
- Confirm Dialog: Shows Yes/No confirmation
- Yes/No/Cancel: Shows 3-option dialog
- Info Dialog: Shows information with OK button
Future Enhancements
Potential improvements could include:
- Modal animations (fade in/out)
- Keyboard navigation support
- Escape key to close
- Custom modal sizes
- Modal stacking support
- Form inputs within modals
- Optional keyboard shortcuts (Enter/Esc)
- Focus management and initial focus button
Dependencies
The modal system requires:
- Angular CommonModule
- RxJS for reactive programming
- No external dependencies
File Structure
src/frontend/src/app/
├── modal.service.ts # Service for modal management
├── modal.component.ts # Modal component
├── modal.component.scss # Modal styles
├── root.component.ts # Updated with modal integration
└── root.component.html # Updated with modal component
This implementation provides a complete, reusable modal dialog system that matches the application's design language and provides flexible configuration options for various dialog types.