[Frontend] AI Image Editing Interface for Property Gallery

Resolved 💬 2 comments Opened Oct 7, 2025 by Spexx01 Closed Nov 29, 2025

Feature Overview

Add AI-powered image editing capabilities to the property gallery with a dedicated editing interface. This feature enables landlords to enhance property images using AI tools like room clearing, wall painting, and staging style selection.

Note: This issue covers frontend only. Backend API integration will be handled separately.

---

User Story

As a landlord, I want to edit my property images using AI tools so that I can improve the visual appeal of my listings without hiring a photographer or designer.

---

Design Specifications

Page Layout

The AI Image Editing page should use a split-panel layout:

  • Left Panel (3/5 width): Large preview of the currently selected image
  • Right Panel (2/5 width): Sticky action panel with editing tools

Action Panel (Right Side)

Four primary action buttons displayed vertically:

  1. Clear Room - Remove furniture and objects from the image
  2. Paint Walls White - Change wall color to white
  3. Choose Staging Style - Opens lightbox to select staging style
  4. Manual Edit - Open manual editing tools (future enhancement)

Each button should:

  • Display an icon + label
  • Show loading state when processing
  • Be disabled when no image is selected
  • Trigger frontend-only logic (backend call placeholder)

Version History (Below Main Panel)

Display a horizontal scrollable timeline of image versions:

  • First thumbnail: Original uploaded image (labeled "Original")
  • Subsequent thumbnails: Added after each edit action (labeled with edit type: "Cleared", "White Walls", "Staging: Modern", etc.)
  • Clicking a thumbnail: Sets it as the main preview
  • Hover state: Reveals a checkbox for comparison selection
  • Max 2 selections: Enable slider comparison when 2 images are checked

Slider Comparison

When exactly 2 images are selected from version history:

  • Replace main preview with a slider comparison view
  • Left side: First selected image
  • Right side: Second selected image
  • Draggable slider in the middle to reveal more/less of each image
  • Close comparison button to return to single image view

Staging Style Lightbox

When "Choose Staging Style" is clicked:

  • Open a lightbox/dialog overlay
  • Display a grid of staging style cards (2-3 columns responsive)
  • Each card shows:
  • Preview thumbnail of the staging style
  • Style name (e.g., "Modern", "Scandinavian", "Industrial", etc.)
  • Clicking a card:
  • Closes the lightbox
  • Triggers frontend logic to apply staging (backend placeholder)
  • Adds new version to history

---

Technical Implementation

1. Create New Components

Component: PropertyImageEditorComponent

Location: src/app/account/components/properties/own/gallery/image-editor/

Files to create:

  • property-image-editor.component.ts
  • property-image-editor.component.html
  • property-image-editor.component.scss

Responsibilities:

  • Main container for the editing interface
  • Manage selected image state
  • Manage version history array
  • Handle comparison mode toggle

Key Properties:

export interface ImageVersion {
  id: string;
  file_url: string;
  label: string;
  created_at: Date;
  is_original: boolean;
}

@Component({
  selector: 'app-property-image-editor',
  templateUrl: './property-image-editor.component.html',
  styleUrls: ['./property-image-editor.component.scss']
})
export class PropertyImageEditorComponent implements OnInit {
  @Input() propertyId!: number;
  @Input() imageId!: number;
  
  currentImage: ImageVersion | null = null;
  versionHistory: ImageVersion[] = [];
  selectedForComparison: ImageVersion[] = [];
  comparisonMode = false;
  isProcessing = false;
  
  constructor(
    private dialog: MatDialog,
    private snackbar: SnackBarService,
    // Backend service to be added later
  ) {}
  
  clearRoom(): void {
    // TODO: Call backend API
    // For now, simulate processing
    this.isProcessing = true;
    setTimeout(() => {
      this.addVersionToHistory('Cleared Room', this.currentImage!.file_url);
      this.isProcessing = false;
    }, 2000);
  }
  
  paintWallsWhite(): void {
    // TODO: Call backend API
    this.isProcessing = true;
    setTimeout(() => {
      this.addVersionToHistory('White Walls', this.currentImage!.file_url);
      this.isProcessing = false;
    }, 2000);
  }
  
  openStagingStyleSelector(): void {
    const dialogRef = this.dialog.open(StagingStyleSelectorDialog, {
      width: '800px',
      data: { imageId: this.currentImage?.id }
    });
    
    dialogRef.afterClosed().subscribe((selectedStyle: string | null) => {
      if (selectedStyle) {
        this.applyStagingStyle(selectedStyle);
      }
    });
  }
  
  applyStagingStyle(style: string): void {
    // TODO: Call backend API
    this.isProcessing = true;
    setTimeout(() => {
      this.addVersionToHistory(`Staging: ${style}`, this.currentImage!.file_url);
      this.isProcessing = false;
    }, 2000);
  }
  
  selectVersion(version: ImageVersion): void {
    if (this.comparisonMode) {
      // In comparison mode, clicking exits comparison
      this.exitComparisonMode();
    } else {
      this.currentImage = version;
    }
  }
  
  toggleComparisonSelection(version: ImageVersion, event: Event): void {
    event.stopPropagation();
    
    const index = this.selectedForComparison.findIndex(v => v.id === version.id);
    if (index > -1) {
      this.selectedForComparison.splice(index, 1);
    } else if (this.selectedForComparison.length < 2) {
      this.selectedForComparison.push(version);
    }
    
    if (this.selectedForComparison.length === 2) {
      this.enterComparisonMode();
    }
  }
  
  enterComparisonMode(): void {
    this.comparisonMode = true;
  }
  
  exitComparisonMode(): void {
    this.comparisonMode = false;
    this.selectedForComparison = [];
  }
  
  private addVersionToHistory(label: string, fileUrl: string): void {
    const newVersion: ImageVersion = {
      id: `version-${Date.now()}`,
      file_url: fileUrl,
      label: label,
      created_at: new Date(),
      is_original: false
    };
    this.versionHistory.push(newVersion);
    this.currentImage = newVersion;
  }
}

HTML Structure:

<div class="image-editor-container">
  <!-- Main editing area -->
  <div class="editor-main">
    <!-- Left panel: Preview -->
    <div class="preview-panel">
      <div *ngIf="!comparisonMode" class="single-image-preview">
        <img [src]="currentImage?.file_url" [alt]="currentImage?.label" />
        <div *ngIf="isProcessing" class="processing-overlay">
          <mat-progress-spinner color="accent" mode="indeterminate"></mat-progress-spinner>
          <p i18n>Processing...</p>
        </div>
      </div>
      
      <div *ngIf="comparisonMode" class="comparison-view">
        <!-- Image comparison slider component -->
        <app-image-comparison-slider 
          [leftImage]="selectedForComparison[0]"
          [rightImage]="selectedForComparison[1]"
          (close)="exitComparisonMode()">
        </app-image-comparison-slider>
      </div>
    </div>
    
    <!-- Right panel: Actions -->
    <div class="action-panel">
      <h3 i18n>AI Editing Tools</h3>
      
      <button mat-flat-button color="accent" 
              (click)="clearRoom()"
              [disabled]="!currentImage || isProcessing">
        <mat-icon>clear_all</mat-icon>
        <span i18n>Clear Room</span>
      </button>
      
      <button mat-flat-button color="accent"
              (click)="paintWallsWhite()"
              [disabled]="!currentImage || isProcessing">
        <mat-icon>format_paint</mat-icon>
        <span i18n>Paint Walls White</span>
      </button>
      
      <button mat-flat-button color="accent"
              (click)="openStagingStyleSelector()"
              [disabled]="!currentImage || isProcessing">
        <mat-icon>style</mat-icon>
        <span i18n>Choose Staging Style</span>
      </button>
      
      <button mat-flat-button color="accent"
              [disabled]="true">
        <mat-icon>edit</mat-icon>
        <span i18n>Manual Edit</span>
        <small i18n>(Coming soon)</small>
      </button>
    </div>
  </div>
  
  <!-- Version history -->
  <div class="version-history">
    <h4 i18n>Version History</h4>
    <div class="history-timeline">
      <div *ngFor="let version of versionHistory"
           class="history-item"
           [class.selected]="currentImage?.id === version.id"
           [class.comparison-selected]="isSelectedForComparison(version)"
           (click)="selectVersion(version)">
        <div class="thumbnail" [style.background-image]="'url(' + version.file_url + ')'">
          <div class="checkbox-overlay" (click)="toggleComparisonSelection(version, $event)">
            <mat-checkbox 
              [checked]="isSelectedForComparison(version)"
              [disabled]="!isSelectedForComparison(version) && selectedForComparison.length >= 2">
            </mat-checkbox>
          </div>
        </div>
        <span class="label">{{ version.label }}</span>
      </div>
    </div>
  </div>
</div>

SCSS Styling:

.image-editor-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 24px;
  
  .editor-main {
    display: flex;
    gap: 24px;
    flex: 1;
    
    .preview-panel {
      flex: 3;
      position: relative;
      background: #f5f5f5;
      border-radius: 8px;
      overflow: hidden;
      
      .single-image-preview {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        
        img {
          max-width: 100%;
          max-height: 100%;
          object-fit: contain;
        }
        
        .processing-overlay {
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background: rgba(0, 0, 0, 0.7);
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          color: white;
        }
      }
    }
    
    .action-panel {
      flex: 2;
      display: flex;
      flex-direction: column;
      gap: 16px;
      padding: 24px;
      background: white;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      position: sticky;
      top: 24px;
      align-self: flex-start;
      
      button {
        width: 100%;
        height: 56px;
        font-size: 16px;
        
        mat-icon {
          margin-right: 8px;
        }
      }
    }
  }
  
  .version-history {
    margin-top: 32px;
    
    .history-timeline {
      display: flex;
      gap: 16px;
      overflow-x: auto;
      padding: 16px 0;
      
      .history-item {
        flex-shrink: 0;
        cursor: pointer;
        text-align: center;
        
        &.selected .thumbnail {
          border: 3px solid #00bcd4;
        }
        
        &.comparison-selected .thumbnail {
          border: 3px solid #ff9800;
        }
        
        .thumbnail {
          width: 120px;
          height: 80px;
          background-size: cover;
          background-position: center;
          border-radius: 4px;
          border: 2px solid transparent;
          position: relative;
          
          &:hover .checkbox-overlay {
            opacity: 1;
          }
          
          .checkbox-overlay {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0;
            transition: opacity 0.2s;
          }
        }
        
        .label {
          display: block;
          margin-top: 8px;
          font-size: 12px;
          color: #666;
        }
      }
    }
  }
}
Component: ImageComparisonSliderComponent

Location: src/app/common/components/image-comparison-slider/

Files to create:

  • image-comparison-slider.component.ts
  • image-comparison-slider.component.html
  • image-comparison-slider.component.scss

Responsibilities:

  • Display two images side-by-side with draggable slider
  • Handle slider dragging interaction
  • Emit close event

Implementation:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { ImageVersion } from '../property-image-editor/property-image-editor.component';

@Component({
  selector: 'app-image-comparison-slider',
  templateUrl: './image-comparison-slider.component.html',
  styleUrls: ['./image-comparison-slider.component.scss']
})
export class ImageComparisonSliderComponent {
  @Input() leftImage!: ImageVersion;
  @Input() rightImage!: ImageVersion;
  @Output() close = new EventEmitter<void>();
  
  sliderPosition = 50; // percentage
  isDragging = false;
  
  onMouseDown(): void {
    this.isDragging = true;
  }
  
  onMouseUp(): void {
    this.isDragging = false;
  }
  
  onMouseMove(event: MouseEvent, container: HTMLElement): void {
    if (!this.isDragging) return;
    
    const rect = container.getBoundingClientRect();
    const x = event.clientX - rect.left;
    this.sliderPosition = (x / rect.width) * 100;
    this.sliderPosition = Math.max(0, Math.min(100, this.sliderPosition));
  }
  
  closeComparison(): void {
    this.close.emit();
  }
}

HTML:

<div class="comparison-container" 
     #container
     (mousemove)="onMouseMove($event, container)"
     (mouseup)="onMouseUp()"
     (mouseleave)="onMouseUp()">
  
  <button mat-icon-button class="close-button" (click)="closeComparison()">
    <mat-icon>close</mat-icon>
  </button>
  
  <div class="image-wrapper">
    <img [src]="rightImage.file_url" alt="Right image" class="full-image" />
    
    <div class="left-image-clip" [style.width.%]="sliderPosition">
      <img [src]="leftImage.file_url" alt="Left image" />
    </div>
    
    <div class="slider-handle" 
         [style.left.%]="sliderPosition"
         (mousedown)="onMouseDown()">
      <div class="handle-line"></div>
      <div class="handle-circle">
        <mat-icon>drag_handle</mat-icon>
      </div>
    </div>
  </div>
  
  <div class="image-labels">
    <span class="left-label">{{ leftImage.label }}</span>
    <span class="right-label">{{ rightImage.label }}</span>
  </div>
</div>

SCSS:

.comparison-container {
  position: relative;
  width: 100%;
  height: 100%;
  user-select: none;
  
  .close-button {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 10;
    background: white;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  }
  
  .image-wrapper {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    
    .full-image {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
    
    .left-image-clip {
      position: absolute;
      top: 0;
      left: 0;
      height: 100%;
      overflow: hidden;
      
      img {
        width: 100%;
        height: 100%;
        object-fit: contain;
      }
    }
    
    .slider-handle {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 4px;
      cursor: ew-resize;
      transform: translateX(-50%);
      
      .handle-line {
        width: 4px;
        height: 100%;
        background: white;
        box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
      }
      
      .handle-circle {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 48px;
        height: 48px;
        border-radius: 50%;
        background: white;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
        display: flex;
        align-items: center;
        justify-content: center;
        
        mat-icon {
          color: #00bcd4;
        }
      }
    }
  }
  
  .image-labels {
    position: absolute;
    bottom: 16px;
    left: 16px;
    right: 16px;
    display: flex;
    justify-content: space-between;
    
    span {
      padding: 8px 16px;
      background: rgba(0, 0, 0, 0.7);
      color: white;
      border-radius: 4px;
      font-size: 14px;
    }
  }
}
Dialog: StagingStyleSelectorDialog

Location: src/app/account/components/properties/own/gallery/staging-style-selector/

Files to create:

  • staging-style-selector.dialog.ts
  • staging-style-selector.dialog.html
  • staging-style-selector.dialog.scss

Responsibilities:

  • Display grid of available staging styles
  • Handle style selection
  • Return selected style to parent component

Implementation:

import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';

export interface StagingStyle {
  id: string;
  name: string;
  thumbnail: string;
  description: string;
}

@Component({
  selector: 'app-staging-style-selector-dialog',
  templateUrl: './staging-style-selector.dialog.html',
  styleUrls: ['./staging-style-selector.dialog.scss']
})
export class StagingStyleSelectorDialog {
  
  // TODO: Fetch from backend in future
  stagingStyles: StagingStyle[] = [
    {
      id: 'modern',
      name: 'Modern',
      thumbnail: '/assets/staging/modern.jpg',
      description: 'Clean lines and minimalist furniture'
    },
    {
      id: 'scandinavian',
      name: 'Scandinavian',
      thumbnail: '/assets/staging/scandinavian.jpg',
      description: 'Light woods and cozy textiles'
    },
    {
      id: 'industrial',
      name: 'Industrial',
      thumbnail: '/assets/staging/industrial.jpg',
      description: 'Exposed brick and metal accents'
    },
    {
      id: 'bohemian',
      name: 'Bohemian',
      thumbnail: '/assets/staging/bohemian.jpg',
      description: 'Eclectic patterns and natural materials'
    },
    {
      id: 'traditional',
      name: 'Traditional',
      thumbnail: '/assets/staging/traditional.jpg',
      description: 'Classic furniture and warm colors'
    },
    {
      id: 'contemporary',
      name: 'Contemporary',
      thumbnail: '/assets/staging/contemporary.jpg',
      description: 'Current trends with bold statements'
    }
  ];
  
  constructor(
    public dialogRef: MatDialogRef<StagingStyleSelectorDialog>,
    @Inject(MAT_DIALOG_DATA) public data: { imageId: string }
  ) {}
  
  selectStyle(style: StagingStyle): void {
    this.dialogRef.close(style.name);
  }
  
  cancel(): void {
    this.dialogRef.close(null);
  }
}

HTML:

<h2 mat-dialog-title i18n>Choose Staging Style</h2>

<mat-dialog-content>
  <div class="staging-styles-grid">
    <div *ngFor="let style of stagingStyles" 
         class="style-card"
         (click)="selectStyle(style)">
      <div class="thumbnail" [style.background-image]="'url(' + style.thumbnail + ')'"></div>
      <h3>{{ style.name }}</h3>
      <p>{{ style.description }}</p>
    </div>
  </div>
</mat-dialog-content>

<mat-dialog-actions align="end">
  <button mat-button (click)="cancel()" i18n>Cancel</button>
</mat-dialog-actions>

SCSS:

mat-dialog-content {
  padding: 24px;
  
  .staging-styles-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
    
    .style-card {
      cursor: pointer;
      border: 2px solid transparent;
      border-radius: 8px;
      padding: 12px;
      transition: all 0.2s;
      
      &:hover {
        border-color: #00bcd4;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        transform: translateY(-2px);
      }
      
      .thumbnail {
        width: 100%;
        height: 150px;
        background-size: cover;
        background-position: center;
        border-radius: 4px;
        margin-bottom: 8px;
      }
      
      h3 {
        margin: 8px 0 4px;
        font-size: 16px;
        font-weight: 600;
      }
      
      p {
        margin: 0;
        font-size: 12px;
        color: #666;
      }
    }
  }
}

2. Update Module Declarations

File: src/app/account/components/properties/own/own-property.module.ts

Add the new components to declarations:

import { PropertyImageEditorComponent } from './gallery/image-editor/property-image-editor.component';
import { StagingStyleSelectorDialog } from './gallery/staging-style-selector/staging-style-selector.dialog';

@NgModule({
  declarations: [
    // ... existing declarations
    PropertyImageEditorComponent,
    StagingStyleSelectorDialog,
  ],
  // ...
})

File: src/app/common/common.module.ts

Add the comparison slider component:

import { ImageComparisonSliderComponent } from './components/image-comparison-slider/image-comparison-slider.component';

@NgModule({
  declarations: [
    // ... existing declarations
    ImageComparisonSliderComponent,
  ],
  exports: [
    // ... existing exports
    ImageComparisonSliderComponent,
  ],
  // ...
})

3. Add Routing

File: src/app/account/components/properties/own/own-property-routing.module.ts

Add a route for the image editor:

{
  path: ':id/edit/gallery/image/:imageId',
  component: PropertyImageEditorComponent,
  data: { title: $localize`Edit Image` }
}

4. Link from Gallery Page

File: src/app/account/components/properties/own/gallery/own-property-gallery.component.html

Update the gallery grid to add an "Edit" button:

<mat-menu #menu="matMenu">
  <button mat-menu-item (click)="setCover(image.id)">
    <mat-icon>collections</mat-icon>
    <span i18n>Make cover</span>
  </button>
  <a mat-menu-item [routerLink]="['/properties', property.id, 'edit', 'gallery', 'image', image.id]">
    <mat-icon>auto_fix_high</mat-icon>
    <span i18n>AI Edit</span>
  </a>
  <button mat-menu-item (click)="deleteItem(image.id)">
    <mat-icon>delete</mat-icon>
    <span i18n>Delete</span>
  </button>
</mat-menu>

---

Integration Notes (Backend Placeholder)

The following methods need backend API integration in the future:

  1. Load image versions: GET /web-app/properties/own/{propertyId}/gallery/{imageId}/versions/
  2. Clear room: POST /web-app/properties/own/{propertyId}/gallery/{imageId}/clear-room/
  3. Paint walls white: POST /web-app/properties/own/{propertyId}/gallery/{imageId}/paint-walls/
  4. Apply staging style: POST /web-app/properties/own/{propertyId}/gallery/{imageId}/apply-staging/
  5. Get staging styles: GET /web-app/staging-styles/

For now, these should use placeholder/mock implementations that:

  • Show a loading spinner for 2 seconds
  • Add a mock version to the history
  • Display success/error snackbar messages

---

Responsive Design

  • Desktop (≥1200px): Full 3/5 + 2/5 layout
  • Tablet (768px - 1199px): Stack panels vertically, action panel full width
  • Mobile (<768px): Stack panels, reduce button sizes, horizontal scroll for version history

---

Testing Checklist

Manual Testing

  • [ ] Image editor page loads with correct image
  • [ ] Action buttons are visible and styled correctly
  • [ ] "Clear Room" button shows loading state and adds version to history
  • [ ] "Paint Walls White" button shows loading state and adds version to history
  • [ ] "Choose Staging Style" opens lightbox with staging style cards
  • [ ] Selecting a staging style closes lightbox and adds version to history
  • [ ] Version history displays all versions horizontally
  • [ ] Clicking a version thumbnail switches the main preview
  • [ ] Hovering over a thumbnail shows checkbox overlay
  • [ ] Selecting 2 thumbnails activates comparison mode
  • [ ] Comparison slider can be dragged left/right
  • [ ] Close button exits comparison mode
  • [ ] Action buttons are disabled when processing
  • [ ] Responsive design works on mobile/tablet/desktop
  • [ ] Navigation back to gallery works correctly
  • [ ] "AI Edit" menu item appears on gallery page

Browser Testing

  • [ ] Chrome (latest)
  • [ ] Firefox (latest)
  • [ ] Safari (latest)
  • [ ] Edge (latest)

---

Acceptance Criteria

  1. ✅ AI Image Editor page accessible from property gallery via "AI Edit" menu item
  2. ✅ Split-panel layout (3/5 preview + 2/5 actions) renders correctly
  3. ✅ Four action buttons displayed with icons and labels
  4. ✅ Action buttons show loading state during processing
  5. ✅ Version history displays horizontally below main panel
  6. ✅ Clicking version thumbnail changes main preview
  7. ✅ Checkbox overlay appears on thumbnail hover
  8. ✅ Selecting exactly 2 thumbnails enables comparison mode
  9. ✅ Comparison slider can be dragged to reveal left/right images
  10. ✅ "Choose Staging Style" opens lightbox with grid of style cards
  11. ✅ Selecting a style closes lightbox and triggers processing
  12. ✅ All interactions work without backend (mock/placeholder logic)
  13. ✅ Responsive design adapts to different screen sizes
  14. ✅ Navigation and routing work correctly

---

Future Enhancements (Out of Scope)

  • Backend API integration for actual AI processing
  • "Manual Edit" functionality (crop, rotate, adjust brightness, etc.)
  • Download edited images
  • Share edited images
  • Batch editing multiple images
  • Undo/redo functionality
  • Save custom staging styles

---

Related Issues

  • Backend API issue (to be created separately)

---

Files to Create/Modify

New Files:

  • src/app/account/components/properties/own/gallery/image-editor/property-image-editor.component.ts
  • src/app/account/components/properties/own/gallery/image-editor/property-image-editor.component.html
  • src/app/account/components/properties/own/gallery/image-editor/property-image-editor.component.scss
  • src/app/common/components/image-comparison-slider/image-comparison-slider.component.ts
  • src/app/common/components/image-comparison-slider/image-comparison-slider.component.html
  • src/app/common/components/image-comparison-slider/image-comparison-slider.component.scss
  • src/app/account/components/properties/own/gallery/staging-style-selector/staging-style-selector.dialog.ts
  • src/app/account/components/properties/own/gallery/staging-style-selector/staging-style-selector.dialog.html
  • src/app/account/components/properties/own/gallery/staging-style-selector/staging-style-selector.dialog.scss

Modified Files:

  • src/app/account/components/properties/own/own-property.module.ts (add declarations)
  • src/app/common/common.module.ts (add comparison slider)
  • src/app/account/components/properties/own/own-property-routing.module.ts (add route)
  • src/app/account/components/properties/own/gallery/own-property-gallery.component.html (add AI Edit menu item)

---

Estimated Effort

8-12 hours for a developer familiar with Angular and Angular Material.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗