@@ -45,41 +45,128 @@ export class LivematePanel extends ReactDevToolsViewBase {
4545 'livemate-prompt-section'
4646 ) ;
4747
48- const promptTextarea = document . createElement ( 'textarea' ) ;
49- promptTextarea . className = 'livemate-prompt-input' ;
50- promptTextarea . placeholder = 'Ask Devmate anything about this app...' ;
51- promptSection . appendChild ( promptTextarea ) ;
52-
53- const sendButton = promptSection . createChild (
54- 'button' ,
55- 'livemate-send-button'
56- ) ;
57- sendButton . textContent = 'Send to Devmate' ;
48+ // Create outer wrapper for centering
49+ const outerWrapper = document . createElement ( 'div' ) ;
50+ outerWrapper . setAttribute ( 'style' , 'display: flex; justify-content: center; align-items: center; min-height: 100%;' ) ;
51+
52+ // Create toolbar container
53+ const toolbarContainer = document . createElement ( 'div' ) ;
54+ toolbarContainer . setAttribute ( 'style' , 'display: flex; flex-direction: column; padding: 20px; gap: 12px; max-width: 800px; width: 100%; margin: 0 20px; border: 1px solid var(--sys-color-divider); border-radius: 8px; background: var(--sys-color-surface);' ) ;
55+
56+ // First row: Inspect button and breadcrumb
57+ const topRow = document . createElement ( 'div' ) ;
58+ topRow . setAttribute ( 'style' , 'display: flex; align-items: center; gap: 8px;' ) ;
59+
60+ // Inspect button
61+ const inspectButton = document . createElement ( 'button' ) ;
62+ inspectButton . textContent = 'Inspect' ;
63+ inspectButton . setAttribute ( 'style' , 'padding: 4px 12px; cursor: pointer;' ) ;
64+ let isInspecting = false ;
65+ inspectButton . addEventListener ( 'click' , ( ) => {
66+ isInspecting = ! isInspecting ;
67+ if ( isInspecting ) {
68+ ( bridge as any ) . send ( 'startInspectingNative' ) ;
69+ inspectButton . textContent = 'Stop Inspecting' ;
70+ } else {
71+ ( bridge as any ) . send ( 'stopInspectingNative' ) ;
72+ inspectButton . textContent = 'Inspect' ;
73+ }
74+ } ) ;
5875
59- const statusArea = promptSection . createChild ( 'div' , 'livemate-status' ) ;
76+ // Breadcrumb view
77+ const breadcrumb = document . createElement ( 'div' ) ;
78+ breadcrumb . setAttribute ( 'style' , 'flex: 1; font-family: monospace; font-size: 12px; color: var(--sys-color-on-surface); display: flex; align-items: center; gap: 4px; flex-wrap: wrap;' ) ;
6079
61- const handleSend = ( ) : void => {
62- const prompt = promptTextarea . value . trim ( ) ;
63- if ( ! prompt ) {
64- statusArea . textContent = 'Please enter a prompt' ;
65- statusArea . className = 'livemate-status error' ;
80+ // Selected component box
81+ const selectedComponentBox = document . createElement ( 'div' ) ;
82+ selectedComponentBox . setAttribute ( 'style' , 'padding: 4px 8px; border: 1px solid var(--sys-color-divider); border-radius: 4px; background: var(--sys-color-surface-variant); font-family: monospace; font-size: 12px; color: var(--sys-color-on-surface);' ) ;
83+ selectedComponentBox . textContent = '' ;
84+
85+ // Function to update breadcrumb with component data
86+ const updateBreadcrumb = ( components : Array < { name : string } > ) : void => {
87+ breadcrumb . innerHTML = '' ;
88+
89+ if ( components . length === 0 ) {
6690 return ;
6791 }
68- statusArea . textContent = 'Sending to Devmate...' ;
69- statusArea . className = 'livemate-status pending' ;
7092
71- (
72- Host . InspectorFrontendHost . InspectorFrontendHostInstance as unknown as {
73- sendToDevmate : ( prompt : string ) => void ,
93+ // Set the selected component to the first one (most specific)
94+ selectedComponentBox . textContent = components [ 0 ] . name ;
95+
96+ // Show remaining components as breadcrumb (skip the first since it's in the selected box)
97+ const breadcrumbComponents = components . slice ( 1 ) ;
98+
99+ breadcrumbComponents . forEach ( ( component , index ) => {
100+ const componentSpan = document . createElement ( 'span' ) ;
101+ componentSpan . textContent = component . name ;
102+ componentSpan . setAttribute ( 'style' , 'cursor: pointer; color: var(--sys-color-primary); text-decoration: underline;' ) ;
103+ componentSpan . addEventListener ( 'click' , ( ) => {
104+ selectedComponentBox . textContent = component . name ;
105+ } ) ;
106+ componentSpan . addEventListener ( 'mouseenter' , ( ) => {
107+ componentSpan . style . opacity = '0.7' ;
108+ } ) ;
109+ componentSpan . addEventListener ( 'mouseleave' , ( ) => {
110+ componentSpan . style . opacity = '1' ;
111+ } ) ;
112+
113+ breadcrumb . appendChild ( componentSpan ) ;
114+
115+ if ( index < breadcrumbComponents . length - 1 ) {
116+ const separator = document . createElement ( 'span' ) ;
117+ separator . textContent = '>' ;
118+ separator . setAttribute ( 'style' , 'color: var(--sys-color-on-surface); opacity: 0.6;' ) ;
119+ breadcrumb . appendChild ( separator ) ;
74120 }
75- ) . sendToDevmate ( prompt ) ;
121+ } ) ;
76122 } ;
77123
78- sendButton . addEventListener ( 'click' , handleSend ) ;
79- promptTextarea . addEventListener ( 'keydown' , e => {
80- if ( e . key === 'Enter' && ( e . metaKey || e . ctrlKey ) ) {
81- handleSend ( ) ;
124+ // Listen for component data from React DevTools
125+ bridge . addListener ( 'viewDataAtPoint' , ( data : unknown ) => {
126+ updateBreadcrumb ( data as Array < { name : string } > ) ;
127+ } ) ;
128+
129+ topRow . appendChild ( inspectButton ) ;
130+ topRow . appendChild ( breadcrumb ) ;
131+ topRow . appendChild ( selectedComponentBox ) ;
132+
133+ // Second row: AI query input and send button
134+ const bottomRow = document . createElement ( 'div' ) ;
135+ bottomRow . setAttribute ( 'style' , 'display: flex; align-items: center; gap: 8px;' ) ;
136+
137+ // AI query text box
138+ const queryInput = document . createElement ( 'textarea' ) ;
139+ queryInput . setAttribute ( 'placeholder' , 'Query to modify component...' ) ;
140+ queryInput . setAttribute ( 'style' , 'flex: 1; padding: 12px 16px; border: 1px solid var(--sys-color-divider); border-radius: 4px; background: var(--sys-color-cdt-base-container); color: var(--sys-color-on-surface); font-size: 14px; min-height: 100px; resize: vertical; font-family: inherit;' ) ;
141+
142+ // Send to devmate button
143+ const sendButton = document . createElement ( 'button' ) ;
144+ sendButton . textContent = 'Send to Devmate' ;
145+ sendButton . setAttribute ( 'style' , 'padding: 4px 12px; cursor: pointer; align-self: flex-end;' ) ;
146+ sendButton . addEventListener ( 'click' , ( ) => {
147+ const query = queryInput . value ;
148+ if ( query . trim ( ) ) {
149+ console . log ( 'Sending to Devmate:' , query ) ;
150+ // statusArea.textContent = 'Sending to Devmate...';
151+ // statusArea.className = 'livemate-status pending';
152+ (
153+ Host . InspectorFrontendHost . InspectorFrontendHostInstance as unknown as {
154+ sendToDevmate : ( prompt : string ) => void ,
155+ }
156+ ) . sendToDevmate ( query ) ;
82157 }
83158 } ) ;
159+
160+ bottomRow . appendChild ( queryInput ) ;
161+ bottomRow . appendChild ( sendButton ) ;
162+
163+ toolbarContainer . appendChild ( topRow ) ;
164+ toolbarContainer . appendChild ( bottomRow ) ;
165+
166+ outerWrapper . appendChild ( toolbarContainer ) ;
167+ this . contentElement . appendChild ( outerWrapper ) ;
168+
169+
170+
84171 }
85172}
0 commit comments