From 4faf9f228483c0f58e09e1bcd968ee48d7f1e2fa Mon Sep 17 00:00:00 2001 From: Louis Knight-Webb Date: Thu, 18 Sep 2025 22:36:00 +0100 Subject: [PATCH] Display textarea (vibe-kanban ad87c626) Instead of showing the contextmenu, we should show a textarea followed by the list of components currently displayed in the contextmenu, as well as a submit button when text has been entered. The components currently in the contextmenu are no longer clickable. For now, when the submit button is pressed, we should just console log. --- apps/cra/src/index.js | 2 +- package.json | 5 +- .../src/ClickToComponent.js | 55 ++-- .../src/ContextMenu.js | 259 ++++++++++-------- .../click-to-react-component/src/types.d.ts | 1 + 5 files changed, 171 insertions(+), 151 deletions(-) diff --git a/apps/cra/src/index.js b/apps/cra/src/index.js index feb4acd..8ec173f 100644 --- a/apps/cra/src/index.js +++ b/apps/cra/src/index.js @@ -8,7 +8,7 @@ import reportWebVitals from './reportWebVitals'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( - + ); diff --git a/package.json b/package.json index 0581aed..786af68 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,5 @@ "@changesets/cli": "^2.23.0", "eslint": "8.13.0", "turbo": "^1.2.16" - }, - "packageManager": "pnpm@6.32.3" -} + } +} \ No newline at end of file diff --git a/packages/click-to-react-component/src/ClickToComponent.js b/packages/click-to-react-component/src/ClickToComponent.js index 11dc0e7..0c5f5e5 100644 --- a/packages/click-to-react-component/src/ClickToComponent.js +++ b/packages/click-to-react-component/src/ClickToComponent.js @@ -27,7 +27,7 @@ export const Trigger = /** @type {const} */ ({ /** * @param {Props} props */ -export function ClickToComponent({ editor = 'vscode', pathModifier }) { +export function ClickToComponent({ editor = 'vscode', port, pathModifier }) { const [state, setState] = React.useState( /** @type {State[keyof State]} */ (State.IDLE) @@ -54,39 +54,39 @@ export function ClickToComponent({ editor = 'vscode', pathModifier }) { ({ active, onToggle }) => html` `, @@ -318,7 +318,7 @@ export function ClickToComponent({ editor = 'vscode', pathModifier }) { if (target instanceof HTMLElement) { window.document.body.dataset.clickToComponent = state target.dataset.clickToComponentTarget = state - + // Set cursor based on trigger type window.document.body.style.setProperty( '--click-to-component-cursor', @@ -379,6 +379,7 @@ export function ClickToComponent({ editor = 'vscode', pathModifier }) { ref=${menuRef} onClose=${onClose} pathModifier=${pathModifier} + port=${port} />`} { // @ts-expect-error - const { onClose, pathModifier } = props + const { onClose, pathModifier, port } = props const [target, setTarget] = React.useState( /** @type {HTMLElement | null} */ @@ -44,17 +44,9 @@ export const ContextMenu = React.forwardRef((props, ref) => { (null) ) - const [activeIndex, setActiveIndex] = React.useState( - /** @type {number | null} */ - (null) - ) - const [open, setOpen] = React.useState(false) - const listItemsRef = React.useRef( - /** @type {Array} */ - ([]) - ) + const [input, setInput] = React.useState('') const { x, @@ -83,15 +75,9 @@ export const ContextMenu = React.forwardRef((props, ref) => { placement: 'right', }) - const { getFloatingProps, getItemProps } = useInteractions([ + const { getFloatingProps } = useInteractions([ useRole(context, { role: 'menu' }), useDismiss(context), - useListNavigation(context, { - listRef: listItemsRef, - activeIndex, - onNavigate: setActiveIndex, - focusItemOnOpen: false, - }), ]) React.useEffect(() => { @@ -207,42 +193,13 @@ export const ContextMenu = React.forwardRef((props, ref) => { filter: drop-shadow(0px 0px 0.5px rgba(0 0 0 / 50%)); } - [data-click-to-component-contextmenu] button { - all: unset; - outline: 0; - display: flex; - flex-direction: column; - width: 100%; - padding: 5px; - border-radius: 4px; - font-size: 13px; - max-width: 50vw; - } - - [data-click-to-component-contextmenu] button:focus, - [data-click-to-component-contextmenu] button:not([disabled]):active { - cursor: pointer; - background: royalblue; - color: white; - box-shadow: var(--shadow-elevation-medium); - } - - [data-click-to-component-contextmenu] button:focus code, - [data-click-to-component-contextmenu] button:not([disabled]):active code { - color: white; - } - - [data-click-to-component-contextmenu] button > * + * { - margin-top: 3px; - } - - [data-click-to-component-contextmenu] button code { + [data-click-to-component-contextmenu] code { color: royalblue; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; } - [data-click-to-component-contextmenu] button code var { + [data-click-to-component-contextmenu] code var { background: rgba(0 0 0 / 5%); cursor: help; border-radius: 3px; @@ -255,25 +212,6 @@ export const ContextMenu = React.forwardRef((props, ref) => { 'Noto Color Emoji'; } - [data-click-to-component-contextmenu] button cite { - font-weight: normal; - font-style: normal; - font-size: 11px; - opacity: 0.5; - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - 'Liberation Mono', 'Courier New', monospace; - } - - [data-click-to-component-contextmenu] button cite data::after { - content: attr(value); - float: right; - padding-left: 15px; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, - 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, - 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', - 'Noto Color Emoji'; - } - [data-click-to-component-contextmenu-arrow] { display: none; position: absolute; @@ -290,64 +228,145 @@ export const ContextMenu = React.forwardRef((props, ref) => { <${FloatingFocusManager} context=${context}> -
- ${instances.map((instance, i) => { - const name = getDisplayNameForInstance(instance) - const source = getSourceForInstance(instance) - const path = getPathToSource(source, pathModifier) - const props = getPropsForInstance(instance) + - - ${'<'}${name} - ${Object.entries(props).map( - ([prop, value]) => html` - ${' '} - ${prop} - ` - )} - ${'>'} - - - - ${source.fileName.replace(/.*(src|pages)/, '$1')} - - - - ` - })} + const components = instances.map((instance) => { + const name = getDisplayNameForInstance(instance) + const source = getSourceForInstance(instance) + const path = getPathToSource(source, pathModifier) + const props = getPropsForInstance(instance) + + return { + name, + props, + source: { + fileName: source.fileName, + lineNumber: source.lineNumber, + columnNumber: source.columnNumber + }, + path + } + }) + + const component_strs = components.map(({ name, path }) => { + return `<${name}> component located in \`${path}\`` + }) + + const component_str = component_strs.join('\nInside ') + + const prompt = `The user has the following feedback:\n\n\`\`\`\n${input}\n\`\`\`\n\nAbout the component stack: ${component_str}`; + + console.log(prompt, port) + + fetch(`http://127.0.0.1:${port}/api/task-attempts/890419d8-150c-485d-ada3-49541475e18b/follow-up`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + prompt, + }), + }) + .then((res) => { + if (!res.ok) { + throw new Error(`HTTP error! Status: ${res.status}`); + } + return res.json(); + }) + .then((data) => { + console.log("Response:", data); + }) + .catch((err) => { + console.error("Error:", err); + }); + + setOpen(false) + onClose?.() + }} + > +