Files
knock-gui/desktop-angular/MODAL_DIALOG_IMPLEMENTATION.md

8.5 KiB

Modal Dialog Implementation Documentation

Overview

This document describes the implementation of two configurable modal dialog systems for the desktop-angular project:

  1. Angular in-app modal component (already integrated into the UI)
  2. 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 modals
  • showConfirm(title, message): Promise<boolean> - Yes/No confirmation dialog
  • showYesNoCancel(title, message): Promise<'yes'|'no'|'cancel'> - Three-option dialog
  • showInfo(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 and ModalComponent
  • Added ModalComponent to component imports
  • Injected ModalService in constructor
  • Added example methods demonstrating modal usage:
    • showCustomModal() - Shows 3-button custom dialog
    • showConfirmDialog() - Shows Yes/No confirmation
    • showYesNoCancelDialog() - Shows Yes/No/Cancel dialog
    • showInfoDialog() - 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 modal BrowserWindow
  • 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) in window.api via ipcRenderer.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:

  1. Primary (style: 'primary'): White background, red text - matches footer buttons
  2. Secondary (style: 'secondary'): Transparent background, white text
  3. 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:

  1. Modal animations (fade in/out)
  2. Keyboard navigation support
  3. Escape key to close
  4. Custom modal sizes
  5. Modal stacking support
  6. Form inputs within modals
  7. Optional keyboard shortcuts (Enter/Esc)
  8. 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.