| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  | import { | 
					
						
							|  |  |  |   DeesElement, | 
					
						
							|  |  |  |   customElement, | 
					
						
							|  |  |  |   html, | 
					
						
							|  |  |  |   property, | 
					
						
							|  |  |  |   css, | 
					
						
							|  |  |  |   cssManager, | 
					
						
							|  |  |  |   state, | 
					
						
							|  |  |  |   type TemplateResult, | 
					
						
							|  |  |  | } from '@design.estate/dees-element'; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  | import * as colors from '../00colors.js'; | 
					
						
							|  |  |  | import { cssGeistFontFamily } from '../00fonts.js'; | 
					
						
							|  |  |  | import { zIndexRegistry } from '../00zindex.js'; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  | import '../dees-icon.js'; | 
					
						
							|  |  |  | import '../dees-button.js'; | 
					
						
							|  |  |  | import '../dees-windowlayer.js'; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  | import { DeesWindowLayer } from '../dees-windowlayer.js'; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  | import { ImageCropper } from './profilepicture.cropper.js'; | 
					
						
							|  |  |  | import type { ProfileShape } from './dees-input-profilepicture.js'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @customElement('dees-profilepicture-modal') | 
					
						
							|  |  |  | export class ProfilePictureModal extends DeesElement { | 
					
						
							|  |  |  |   @property({ type: String }) | 
					
						
							|  |  |  |   public initialImage: string = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ type: String }) | 
					
						
							|  |  |  |   public shape: ProfileShape = 'round'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |   @property({ type: Number }) | 
					
						
							|  |  |  |   public outputSize: number = 800; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ type: Number }) | 
					
						
							|  |  |  |   public outputQuality: number = 0.95; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |   @state() | 
					
						
							|  |  |  |   private currentStep: 'crop' | 'preview' = 'crop'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @state() | 
					
						
							|  |  |  |   private croppedImage: string = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @state() | 
					
						
							|  |  |  |   private isProcessing: boolean = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private cropper: ImageCropper | null = null; | 
					
						
							|  |  |  |   private windowLayer: any; | 
					
						
							|  |  |  |   private zIndex: number = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public static styles = [ | 
					
						
							|  |  |  |     cssManager.defaultStyles, | 
					
						
							|  |  |  |     css`
 | 
					
						
							|  |  |  |       :host { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         font-family: ${cssGeistFontFamily}; | 
					
						
							|  |  |  |         color: ${cssManager.bdTheme('#333', '#fff')}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         position: fixed; | 
					
						
							|  |  |  |         top: 0; | 
					
						
							|  |  |  |         left: 0; | 
					
						
							|  |  |  |         right: 0; | 
					
						
							|  |  |  |         bottom: 0; | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							|  |  |  |         justify-content: center; | 
					
						
							|  |  |  |         z-index: var(--z-index); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .modal-container { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         background: ${cssManager.bdTheme('#ffffff', '#0a0a0a')}; | 
					
						
							|  |  |  |         border-radius: 12px; | 
					
						
							|  |  |  |         border: 1px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.08)')}; | 
					
						
							|  |  |  |         box-shadow: ${cssManager.bdTheme( | 
					
						
							|  |  |  |           '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', | 
					
						
							|  |  |  |           '0 20px 25px -5px rgba(0, 0, 0, 0.3), 0 10px 10px -5px rgba(0, 0, 0, 0.2)' | 
					
						
							|  |  |  |         )}; | 
					
						
							|  |  |  |         width: 480px; | 
					
						
							|  |  |  |         max-width: calc(100vw - 32px); | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         display: flex; | 
					
						
							|  |  |  |         flex-direction: column; | 
					
						
							|  |  |  |         overflow: hidden; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         transform: translateY(10px) scale(0.98); | 
					
						
							|  |  |  |         opacity: 0; | 
					
						
							|  |  |  |         animation: modalShow 0.25s cubic-bezier(0.4, 0, 0.2, 1) forwards; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |       @keyframes modalShow { | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         to { | 
					
						
							|  |  |  |           opacity: 1; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |           transform: translateY(0px) scale(1); | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .modal-header { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         height: 52px; | 
					
						
							|  |  |  |         padding: 0 20px; | 
					
						
							|  |  |  |         border-bottom: 1px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.06)', 'rgba(255, 255, 255, 0.06)')}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         display: flex; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         justify-content: center; | 
					
						
							|  |  |  |         position: relative; | 
					
						
							|  |  |  |         flex-shrink: 0; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .modal-title { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         font-size: 15px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         font-weight: 600; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         color: ${cssManager.bdTheme('#09090b', '#fafafa')}; | 
					
						
							|  |  |  |         letter-spacing: -0.01em; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .close-button { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         position: absolute; | 
					
						
							|  |  |  |         right: 10px; | 
					
						
							|  |  |  |         top: 50%; | 
					
						
							|  |  |  |         transform: translateY(-50%); | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         width: 32px; | 
					
						
							|  |  |  |         height: 32px; | 
					
						
							|  |  |  |         border: none; | 
					
						
							|  |  |  |         background: transparent; | 
					
						
							|  |  |  |         cursor: pointer; | 
					
						
							|  |  |  |         border-radius: 8px; | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							|  |  |  |         justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         color: ${cssManager.bdTheme('#71717a', '#71717a')}; | 
					
						
							|  |  |  |         transition: all 0.15s ease; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .close-button:hover { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.05)', 'rgba(255, 255, 255, 0.05)')}; | 
					
						
							|  |  |  |         color: ${cssManager.bdTheme('#09090b', '#fafafa')}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .close-button:active { | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.08)')}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .modal-body { | 
					
						
							|  |  |  |         flex: 1; | 
					
						
							|  |  |  |         padding: 24px; | 
					
						
							|  |  |  |         overflow-y: auto; | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         flex-direction: column; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         gap: 20px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .cropper-container { | 
					
						
							|  |  |  |         width: 100%; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         max-width: 360px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         aspect-ratio: 1; | 
					
						
							|  |  |  |         position: relative; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         background: ${cssManager.bdTheme('#000000', '#000000')}; | 
					
						
							|  |  |  |         border-radius: 12px; | 
					
						
							|  |  |  |         overflow: hidden; | 
					
						
							|  |  |  |         box-shadow: ${cssManager.bdTheme( | 
					
						
							|  |  |  |           'inset 0 2px 4px rgba(0, 0, 0, 0.06)', | 
					
						
							|  |  |  |           'inset 0 2px 4px rgba(0, 0, 0, 0.2)' | 
					
						
							|  |  |  |         )}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .preview-container { | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         flex-direction: column; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         gap: 20px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .preview-image { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         width: 180px; | 
					
						
							|  |  |  |         height: 180px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         object-fit: cover; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         border: 4px solid ${cssManager.bdTheme('#ffffff', '#18181b')}; | 
					
						
							|  |  |  |         box-shadow: ${cssManager.bdTheme( | 
					
						
							|  |  |  |           '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', | 
					
						
							|  |  |  |           '0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2)' | 
					
						
							|  |  |  |         )}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .preview-image.round { | 
					
						
							|  |  |  |         border-radius: 50%; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .preview-image.square { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         border-radius: 16px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .success-message { | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         gap: 10px; | 
					
						
							|  |  |  |         padding: 10px 20px; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('#10b981', '#10b981')}; | 
					
						
							|  |  |  |         color: white; | 
					
						
							|  |  |  |         border-radius: 100px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         font-weight: 500; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         font-size: 14px; | 
					
						
							|  |  |  |         animation: successPulse 0.4s ease-out; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @keyframes successPulse { | 
					
						
							|  |  |  |         0% { transform: scale(0.9); opacity: 0; } | 
					
						
							|  |  |  |         50% { transform: scale(1.02); } | 
					
						
							|  |  |  |         100% { transform: scale(1); opacity: 1; } | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .modal-footer { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         padding: 20px 24px; | 
					
						
							|  |  |  |         border-top: 1px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.06)', 'rgba(255, 255, 255, 0.06)')}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         display: flex; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         gap: 10px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         justify-content: flex-end; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .instructions { | 
					
						
							|  |  |  |         text-align: center; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; | 
					
						
							|  |  |  |         font-size: 13px; | 
					
						
							|  |  |  |         line-height: 1.5; | 
					
						
							|  |  |  |         max-width: 320px; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .loading-spinner { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         width: 40px; | 
					
						
							|  |  |  |         height: 40px; | 
					
						
							|  |  |  |         border: 3px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')}; | 
					
						
							|  |  |  |         border-top-color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')}; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         border-radius: 50%; | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |         animation: spin 0.6s linear infinite; | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @keyframes spin { | 
					
						
							|  |  |  |         to { | 
					
						
							|  |  |  |           transform: rotate(360deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       @media (max-width: 768px) { | 
					
						
							|  |  |  |         .modal-container { | 
					
						
							|  |  |  |           width: calc(100vw - 32px); | 
					
						
							|  |  |  |           margin: 16px; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         .modal-body { | 
					
						
							|  |  |  |           padding: 24px; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |     `,
 | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async connectedCallback() { | 
					
						
							|  |  |  |     super.connectedCallback(); | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |     // Create window layer first (it will get its own z-index)
 | 
					
						
							|  |  |  |     this.windowLayer = await DeesWindowLayer.createAndShow({ | 
					
						
							|  |  |  |       blur: true, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     this.windowLayer.addEventListener('click', () => this.close()); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // Now get z-index for modal (will be above window layer)
 | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |     this.zIndex = zIndexRegistry.getNextZIndex(); | 
					
						
							|  |  |  |     this.style.setProperty('--z-index', this.zIndex.toString()); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // Register with z-index registry
 | 
					
						
							|  |  |  |     zIndexRegistry.register(this, this.zIndex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async disconnectedCallback() { | 
					
						
							|  |  |  |     super.disconnectedCallback(); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // Cleanup
 | 
					
						
							|  |  |  |     if (this.cropper) { | 
					
						
							|  |  |  |       this.cropper.destroy(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (this.windowLayer) { | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |       await this.windowLayer.destroy(); | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // Unregister from z-index registry
 | 
					
						
							|  |  |  |     zIndexRegistry.unregister(this); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   render(): TemplateResult { | 
					
						
							|  |  |  |     return html`
 | 
					
						
							|  |  |  |       <div class="modal-container" @click=${(e: Event) => e.stopPropagation()}> | 
					
						
							|  |  |  |         <div class="modal-header"> | 
					
						
							|  |  |  |           <h3 class="modal-title"> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |             ${this.currentStep === 'crop' ? 'Adjust Image' : 'Success'} | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |           </h3> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |           <button class="close-button" @click=${this.close} title="Close"> | 
					
						
							|  |  |  |             <dees-icon icon="lucide:x" iconSize="16"></dees-icon> | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |           </button> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         <div class="modal-body"> | 
					
						
							|  |  |  |           ${this.currentStep === 'crop' ? html`
 | 
					
						
							|  |  |  |             <div class="instructions"> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |               Position and resize the square to select your profile area | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |             </div> | 
					
						
							|  |  |  |             <div class="cropper-container" id="cropperContainer"></div> | 
					
						
							|  |  |  |           ` : html` | 
					
						
							|  |  |  |             <div class="preview-container"> | 
					
						
							|  |  |  |               ${this.isProcessing ? html`
 | 
					
						
							|  |  |  |                 <div class="loading-spinner"></div> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |                 <div class="instructions">Saving...</div> | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |               ` : html` | 
					
						
							|  |  |  |                 <img  | 
					
						
							|  |  |  |                   class="preview-image ${this.shape}"  | 
					
						
							|  |  |  |                   src="${this.croppedImage}"  | 
					
						
							|  |  |  |                   alt="Cropped preview" | 
					
						
							|  |  |  |                 /> | 
					
						
							|  |  |  |                 <div class="success-message"> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |                   <dees-icon icon="lucide:check" iconSize="16"></dees-icon> | 
					
						
							|  |  |  |                   <span>Looking good!</span> | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |                 </div> | 
					
						
							|  |  |  |               `}
 | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |           `}
 | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         <div class="modal-footer"> | 
					
						
							|  |  |  |           ${this.currentStep === 'crop' ? html`
 | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |             <dees-button type="destructive" size="sm" @click=${this.close}> | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |               Cancel | 
					
						
							|  |  |  |             </dees-button> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |             <dees-button type="default" size="sm" @click=${this.handleCrop}> | 
					
						
							|  |  |  |               Save | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |             </dees-button> | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |           ` : ''}
 | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |         </div> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `;
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async firstUpdated() { | 
					
						
							|  |  |  |     if (this.currentStep === 'crop') { | 
					
						
							|  |  |  |       await this.initializeCropper(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private async initializeCropper(): Promise<void> { | 
					
						
							|  |  |  |     await this.updateComplete; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     const container = this.shadowRoot!.getElementById('cropperContainer'); | 
					
						
							|  |  |  |     if (!container) return; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     this.cropper = new ImageCropper({ | 
					
						
							|  |  |  |       container, | 
					
						
							|  |  |  |       image: this.initialImage, | 
					
						
							|  |  |  |       shape: this.shape, | 
					
						
							|  |  |  |       aspectRatio: 1, | 
					
						
							| 
									
										
										
										
											2025-06-30 12:02:02 +00:00
										 |  |  |       outputSize: this.outputSize, | 
					
						
							|  |  |  |       outputQuality: this.outputQuality, | 
					
						
							| 
									
										
										
										
											2025-06-30 11:35:38 +00:00
										 |  |  |     }); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     await this.cropper.initialize(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private async handleCrop(): Promise<void> { | 
					
						
							|  |  |  |     if (!this.cropper) return; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       this.isProcessing = true; | 
					
						
							|  |  |  |       this.currentStep = 'preview'; | 
					
						
							|  |  |  |       await this.updateComplete; | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       // Get cropped image
 | 
					
						
							|  |  |  |       const croppedData = await this.cropper.getCroppedImage(); | 
					
						
							|  |  |  |       this.croppedImage = croppedData; | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       // Simulate processing time for better UX
 | 
					
						
							|  |  |  |       await new Promise(resolve => setTimeout(resolve, 800)); | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       this.isProcessing = false; | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       // Emit save event
 | 
					
						
							|  |  |  |       this.dispatchEvent(new CustomEvent('save', { | 
					
						
							|  |  |  |         detail: { croppedImage: this.croppedImage }, | 
					
						
							|  |  |  |         bubbles: true, | 
					
						
							|  |  |  |         composed: true | 
					
						
							|  |  |  |       })); | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       // Auto close after showing success
 | 
					
						
							|  |  |  |       setTimeout(() => { | 
					
						
							|  |  |  |         this.close(); | 
					
						
							|  |  |  |       }, 1500); | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							|  |  |  |       console.error('Error cropping image:', error); | 
					
						
							|  |  |  |       this.isProcessing = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private close(): void { | 
					
						
							|  |  |  |     this.remove(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |