Skip to content

Commit 90b518c

Browse files
committed
Update component selector
1 parent e4d9786 commit 90b518c

1 file changed

Lines changed: 113 additions & 26 deletions

File tree

front_end/panels/livemate/LivematePanel.ts

Lines changed: 113 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)