@@ -8,6 +8,7 @@ document.addEventListener('alpine:init', () => {
88 Alpine . data ( 'mageforgeInspector' , ( ) => ( {
99 isOpen : false ,
1010 isPickerActive : false ,
11+ isPinned : false , // Badge is locked after clicking an element
1112 hoveredElement : null ,
1213 selectedElement : null ,
1314 highlightBox : null ,
@@ -248,7 +249,9 @@ document.addEventListener('alpine:init', () => {
248249 */
249250 closeInspector ( ) {
250251 this . isOpen = false ;
252+ this . isPinned = false ;
251253 this . deactivatePicker ( ) ;
254+ this . hideHighlight ( ) ;
252255 this . $dispatch ( 'mageforge:inspector:closed' ) ;
253256 this . updateFloatingButton ( ) ;
254257 } ,
@@ -276,9 +279,19 @@ document.addEventListener('alpine:init', () => {
276279 }
277280
278281 document . removeEventListener ( 'mousemove' , this . mouseMoveHandler ) ;
279- document . removeEventListener ( 'click' , this . clickHandler , false ) ;
282+
283+ // Keep click handler active if pinned (for click-outside detection)
284+ if ( ! this . isPinned ) {
285+ document . removeEventListener ( 'click' , this . clickHandler , false ) ;
286+ }
287+
280288 document . body . style . cursor = '' ;
281- this . hideHighlight ( ) ;
289+
290+ // Only hide if not pinned
291+ if ( ! this . isPinned ) {
292+ this . hideHighlight ( ) ;
293+ }
294+
282295 this . hoveredElement = null ;
283296 this . lastBadgeUpdate = 0 ;
284297 } ,
@@ -289,6 +302,9 @@ document.addEventListener('alpine:init', () => {
289302 handleMouseMove ( e ) {
290303 if ( ! this . isPickerActive ) return ;
291304
305+ // Don't update if badge is pinned
306+ if ( this . isPinned ) return ;
307+
292308 // Don't update if mouse is over the floating button
293309 if ( this . floatingButton && this . floatingButton . contains ( e . target ) ) {
294310 return ;
@@ -338,9 +354,20 @@ document.addEventListener('alpine:init', () => {
338354 * Handle click on element
339355 */
340356 handleClick ( e ) {
357+ // Handle click outside badge when pinned
358+ if ( this . isPinned && this . infoBadge ) {
359+ // Check if click is outside badge
360+ if ( ! this . infoBadge . contains ( e . target ) && ! this . floatingButton . contains ( e . target ) ) {
361+ this . unpinBadge ( ) ;
362+ return ;
363+ }
364+ // Click inside badge - do nothing, let it stay open
365+ return ;
366+ }
367+
341368 if ( ! this . isPickerActive ) return ;
342369
343- // Don't handle clicks on the info badge
370+ // Don't handle clicks on the info badge during picking
344371 if ( this . infoBadge && ( this . infoBadge . contains ( e . target ) || this . infoBadge === e . target ) ) {
345372 return ;
346373 }
@@ -353,11 +380,34 @@ document.addEventListener('alpine:init', () => {
353380 if ( element ) {
354381 this . selectedElement = element ;
355382 this . updatePanelData ( element ) ;
356- // Keep panel open but stop picking
357- this . deactivatePicker ( ) ;
383+ this . pinBadge ( ) ;
384+ }
385+ } ,
386+
387+ /**
388+ * Pin the badge after element selection
389+ */
390+ pinBadge ( ) {
391+ this . isPinned = true ;
392+ this . deactivatePicker ( ) ;
393+ // Keep highlight and badge visible
394+ // Update badge to show close button
395+ if ( this . selectedElement ) {
396+ this . buildBadgeContent ( this . selectedElement ) ;
358397 }
359398 } ,
360399
400+ /**
401+ * Unpin and close the badge
402+ // Remove click handler now that we're unpinned
403+ document.removeEventListener('click', this.clickHandler, false);
404+ */
405+ unpinBadge ( ) {
406+ this . isPinned = false ;
407+ this . hideHighlight ( ) ;
408+ this . selectedElement = null ;
409+ } ,
410+
361411 /**
362412 * Find nearest inspectable element
363413 */
@@ -480,13 +530,73 @@ document.addEventListener('alpine:init', () => {
480530 // Clear badge
481531 this . infoBadge . innerHTML = '' ;
482532
533+ // Add close button if pinned
534+ if ( this . isPinned ) {
535+ this . infoBadge . appendChild ( this . createCloseButton ( ) ) ;
536+ }
537+
483538 // Create tab system
484539 this . createTabSystem ( data , element ) ;
485540
486541 // Branding footer
487542 this . infoBadge . appendChild ( this . createBrandingFooter ( ) ) ;
488543 } ,
489544
545+ /**
546+ * Create close button for pinned badge
547+ */
548+ createCloseButton ( ) {
549+ const closeBtn = document . createElement ( 'button' ) ;
550+ closeBtn . type = 'button' ;
551+ closeBtn . className = 'mageforge-inspector-close' ;
552+ closeBtn . innerHTML = '✕' ;
553+ closeBtn . title = 'Close (or click outside)' ;
554+ closeBtn . style . cssText = `
555+ position: absolute;
556+ top: 12px;
557+ right: 12px;
558+ width: 28px;
559+ height: 28px;
560+ background: rgba(255, 255, 255, 0.05);
561+ border: 1px solid rgba(255, 255, 255, 0.1);
562+ border-radius: 6px;
563+ color: #94a3b8;
564+ font-size: 16px;
565+ font-weight: 600;
566+ cursor: pointer;
567+ display: flex;
568+ align-items: center;
569+ justify-content: center;
570+ transition: all 0.2s ease;
571+ z-index: 10;
572+ font-family: inherit;
573+ line-height: 1;
574+ padding: 0;
575+ ` ;
576+
577+ closeBtn . onmouseenter = ( ) => {
578+ closeBtn . style . background = 'rgba(239, 68, 68, 0.15)' ;
579+ closeBtn . style . borderColor = 'rgba(239, 68, 68, 0.3)' ;
580+ closeBtn . style . color = '#ef4444' ;
581+ closeBtn . style . transform = 'scale(1.05)' ;
582+ } ;
583+
584+ closeBtn . onmouseleave = ( ) => {
585+ closeBtn . style . background = 'rgba(255, 255, 255, 0.05)' ;
586+ closeBtn . style . borderColor = 'rgba(255, 255, 255, 0.1)' ;
587+ closeBtn . style . color = '#94a3b8' ;
588+ closeBtn . style . transform = 'scale(1)' ;
589+ } ;
590+
591+ closeBtn . onclick = ( e ) => {
592+ e . preventDefault ( ) ;
593+ e . stopPropagation ( ) ;
594+ this . unpinBadge ( ) ;
595+ } ;
596+
597+ return closeBtn ;
598+ } ,
599+
490600 /**
491601 * Create tab system for inspector
492602 */
@@ -688,9 +798,8 @@ document.addEventListener('alpine:init', () => {
688798 * Render structure sections (template, block, module, etc.)
689799 */
690800 renderStructureSections ( data , container ) {
691- // Template section with override indicator
692- const templateDisplay = data . isOverride ? '🔧 ' + data . template : data . template ;
693- container . appendChild ( this . createInfoSection ( '📄 Template' , templateDisplay , '#60a5fa' ) ) ;
801+ // Template section
802+ container . appendChild ( this . createInfoSection ( '📄 Template' , data . template , '#60a5fa' ) ) ;
694803
695804 // Block section
696805 container . appendChild ( this . createInfoSection ( '📦 Block' , data . blockClass , '#a78bfa' ) ) ;
0 commit comments