From 3674e2bd0c1f98a6729ebaedf6a2cb3b25d22082 Mon Sep 17 00:00:00 2001 From: spencrmartin Date: Wed, 24 Sep 2025 21:15:02 -0400 Subject: [PATCH] Clean up: Remove debug Python scripts and console.log statements - Removed all temporary Python debugging scripts from root directory - Cleaned up debug console.log statements from ChatInput.tsx and RichChatInput.tsx - Kept only the core implementation files for the rich text input feature --- add_backspace_pill_removal.py | 62 ------ add_cursor_blink_animation.py | 48 ----- add_mention_debugging.py | 84 --------- add_tailwind_blink_class.py | 27 --- add_visible_text_selection.py | 105 ----------- complete_mention_pill_rendering.py | 181 ------------------ comprehensive_action_fix.py | 98 ---------- create_mention_pill_component.py | 67 ------- debug_action_flow.py | 75 -------- debug_action_popover.py | 61 ------ debug_richtextinput.py | 97 ---------- fix_action_popover_order.py | 80 -------- fix_action_popover_state.py | 81 -------- fix_action_selection.py | 90 --------- fix_chatinput.py | 106 ----------- fix_correct_tailwind_classes.py | 34 ---- fix_cursor_and_placeholder_styling.py | 34 ---- fix_cursor_blink_with_css.py | 29 --- fix_cursor_line_break_logic.py | 112 ----------- fix_cursor_placeholder_order.py | 48 ----- fix_cursor_positioning.py | 29 --- fix_cursor_to_black_blinking.py | 33 ---- fix_cursor_vertical_alignment.py | 30 --- fix_dark_mode_cursor_and_text.py | 33 ---- fix_import_issue.py | 38 ---- fix_inline_message_display.py | 87 --------- fix_input_spacing.py | 110 ----------- fix_mention_file_select_properly.py | 78 -------- fix_message_pill_line_breaks.py | 28 --- fix_multiline_cursor_positioning.py | 48 ----- fix_placeholder_behavior.py | 45 ----- fix_placeholder_color_lighter.py | 22 --- fix_placeholder_color_medium.py | 22 --- fix_placeholder_positioning.py | 49 ----- fix_placeholder_text_shift.py | 57 ------ fix_regex_error.py | 34 ---- fix_richtextinput_integration.py | 43 ----- fix_richtextinput_processing_loop.py | 169 ----------------- fix_selection_alignment.py | 118 ------------ fix_selection_visibility.py | 124 ------------ fix_text_selection_behavior.py | 133 ------------- fix_text_selection_functionality.py | 136 -------------- pr_description.md | 80 ++++++++ replace_textarea.py | 60 ------ simple_inline_pills.py | 50 ----- test_action_flow.py | 67 ------- test_basic_functionality.py | 80 -------- test_mention_functionality.py | 63 ------- update_chatinput_mention_handling.py | 67 ------- update_mention_pill_styling.py | 31 --- update_message_content_for_mentions.py | 249 ------------------------- update_pill_icons.py | 70 ------- update_richtextinput_for_mentions.py | 93 --------- 53 files changed, 80 insertions(+), 3815 deletions(-) delete mode 100644 add_backspace_pill_removal.py delete mode 100644 add_cursor_blink_animation.py delete mode 100644 add_mention_debugging.py delete mode 100644 add_tailwind_blink_class.py delete mode 100644 add_visible_text_selection.py delete mode 100644 complete_mention_pill_rendering.py delete mode 100644 comprehensive_action_fix.py delete mode 100644 create_mention_pill_component.py delete mode 100644 debug_action_flow.py delete mode 100644 debug_action_popover.py delete mode 100644 debug_richtextinput.py delete mode 100644 fix_action_popover_order.py delete mode 100644 fix_action_popover_state.py delete mode 100644 fix_action_selection.py delete mode 100644 fix_chatinput.py delete mode 100644 fix_correct_tailwind_classes.py delete mode 100644 fix_cursor_and_placeholder_styling.py delete mode 100644 fix_cursor_blink_with_css.py delete mode 100644 fix_cursor_line_break_logic.py delete mode 100644 fix_cursor_placeholder_order.py delete mode 100644 fix_cursor_positioning.py delete mode 100644 fix_cursor_to_black_blinking.py delete mode 100644 fix_cursor_vertical_alignment.py delete mode 100644 fix_dark_mode_cursor_and_text.py delete mode 100644 fix_import_issue.py delete mode 100644 fix_inline_message_display.py delete mode 100644 fix_input_spacing.py delete mode 100644 fix_mention_file_select_properly.py delete mode 100644 fix_message_pill_line_breaks.py delete mode 100644 fix_multiline_cursor_positioning.py delete mode 100644 fix_placeholder_behavior.py delete mode 100644 fix_placeholder_color_lighter.py delete mode 100644 fix_placeholder_color_medium.py delete mode 100644 fix_placeholder_positioning.py delete mode 100644 fix_placeholder_text_shift.py delete mode 100644 fix_regex_error.py delete mode 100644 fix_richtextinput_integration.py delete mode 100644 fix_richtextinput_processing_loop.py delete mode 100644 fix_selection_alignment.py delete mode 100644 fix_selection_visibility.py delete mode 100644 fix_text_selection_behavior.py delete mode 100644 fix_text_selection_functionality.py create mode 100644 pr_description.md delete mode 100644 replace_textarea.py delete mode 100644 simple_inline_pills.py delete mode 100644 test_action_flow.py delete mode 100644 test_basic_functionality.py delete mode 100644 test_mention_functionality.py delete mode 100644 update_chatinput_mention_handling.py delete mode 100644 update_mention_pill_styling.py delete mode 100644 update_message_content_for_mentions.py delete mode 100644 update_pill_icons.py delete mode 100644 update_richtextinput_for_mentions.py diff --git a/add_backspace_pill_removal.py b/add_backspace_pill_removal.py deleted file mode 100644 index b5580b7e9e..0000000000 --- a/add_backspace_pill_removal.py +++ /dev/null @@ -1,62 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Adding backspace removal for both action and mention pills...") - -# Find the current backspace handling and enhance it -old_backspace_handling = ''' // Handle backspace on action pills - if (e.key === 'Backspace') { - const cursorPos = e.currentTarget.selectionStart; - const beforeCursor = value.slice(0, cursorPos); - - // Check if cursor is right after an action pill - const actionMatch = beforeCursor.match(/\[([^\]]+)\]$/); - if (actionMatch) { - e.preventDefault(); - handleRemoveAction(actionMatch[1]); - return; - } - }''' - -new_backspace_handling = ''' // Handle backspace on action and mention pills - if (e.key === 'Backspace') { - const cursorPos = e.currentTarget.selectionStart; - const beforeCursor = value.slice(0, cursorPos); - - console.log('๐Ÿ”™ Backspace pressed, cursor at:', cursorPos); - console.log('๐Ÿ”™ Text before cursor:', beforeCursor); - - // Check if cursor is right after an action pill [Action] - const actionMatch = beforeCursor.match(/\[([^\]]+)\]$/); - if (actionMatch) { - console.log('๐Ÿ”™ Found action pill to remove:', actionMatch[1]); - e.preventDefault(); - handleRemoveAction(actionMatch[1]); - return; - } - - // Check if cursor is right after a mention pill @filename - const mentionMatch = beforeCursor.match(/@([^\s]+)$/); - if (mentionMatch) { - console.log('๐Ÿ”™ Found mention pill to remove:', mentionMatch[1]); - e.preventDefault(); - handleRemoveMention(mentionMatch[1]); - return; - } - }''' - -content = content.replace(old_backspace_handling, new_backspace_handling) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Added backspace removal for pills:") -print(" - Enhanced existing action pill removal") -print(" - Added mention pill removal (@filename)") -print(" - Added debugging logs for backspace events") -print(" - Now supports removing both types of pills with backspace") -print(" - Pills will be removed as complete units") diff --git a/add_cursor_blink_animation.py b/add_cursor_blink_animation.py deleted file mode 100644 index f4df823a2e..0000000000 --- a/add_cursor_blink_animation.py +++ /dev/null @@ -1,48 +0,0 @@ -import re - -# Read the main.css file -with open('ui/desktop/src/styles/main.css', 'r') as f: - content = f.read() - -print("Adding cursor blink animation to main.css...") - -# Find the animations section and add the blink animation -animations_section = '''/* animations */ -@keyframes appear { - from { - opacity: 0; - } - to { - opacity: 1; - } -}''' - -new_animations_section = '''/* animations */ -@keyframes appear { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes blink { - 0%, 50% { - opacity: 1; - } - 51%, 100% { - opacity: 0; - } -}''' - -content = content.replace(animations_section, new_animations_section) - -# Write the modified content back -with open('ui/desktop/src/styles/main.css', 'w') as f: - f.write(content) - -print("โœ… Added cursor blink animation to main.css") -print(" - @keyframes blink: 0-50% visible, 51-100% hidden") -print(" - Creates a regular text cursor blinking effect") -print(" - Can be used with 'animate-blink' class") diff --git a/add_mention_debugging.py b/add_mention_debugging.py deleted file mode 100644 index dc33f14b8a..0000000000 --- a/add_mention_debugging.py +++ /dev/null @@ -1,84 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Adding comprehensive debugging for mention detection...") - -# Find the mention regex section and add more debugging -old_mention_detection = ''' // Find all mention matches - let mentionMatch; - mentionRegex.lastIndex = 0; // Reset regex - while ((mentionMatch = mentionRegex.exec(value)) !== null) { - allMatches.push({ - type: 'mention', - match: mentionMatch, - index: mentionMatch.index, - length: mentionMatch[0].length, - content: mentionMatch[1] // filename without @ - }); - }''' - -new_mention_detection = ''' // Find all mention matches - let mentionMatch; - mentionRegex.lastIndex = 0; // Reset regex - console.log('๐Ÿ” Searching for mentions in value:', value); - console.log('๐Ÿ” Using mention regex:', mentionRegex); - while ((mentionMatch = mentionRegex.exec(value)) !== null) { - console.log('๐Ÿ“ Found mention match:', mentionMatch); - allMatches.push({ - type: 'mention', - match: mentionMatch, - index: mentionMatch.index, - length: mentionMatch[0].length, - content: mentionMatch[1] // filename without @ - }); - }''' - -content = content.replace(old_mention_detection, new_mention_detection) - -# Also add debugging after sorting matches -old_sort_section = ''' // Sort matches by position - allMatches.sort((a, b) => a.index - b.index); - - console.log('๐Ÿ” Found matches:', allMatches);''' - -new_sort_section = ''' // Sort matches by position - allMatches.sort((a, b) => a.index - b.index); - - console.log('๐Ÿ” All matches found:', allMatches); - console.log('๐Ÿ“Š Match breakdown:', { - actions: allMatches.filter(m => m.type === 'action').length, - mentions: allMatches.filter(m => m.type === 'mention').length, - total: allMatches.length - });''' - -content = content.replace(old_sort_section, new_sort_section) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Added comprehensive debugging:") -print(" - Debug logs for mention regex search") -print(" - Debug logs for found mention matches") -print(" - Match breakdown statistics") -print(" - Should help identify if mentions are being detected") - -# Also let's test the regex pattern directly -import re - -test_strings = [ - "@filename.txt", - "Hello @test.py world", - "@folder/file.js", - "Multiple @file1.txt and @file2.py mentions" -] - -mention_regex = re.compile(r'@([^\s]+)') - -print("\n๐Ÿงช Testing mention regex pattern:") -for test in test_strings: - matches = mention_regex.findall(test) - print(f" '{test}' โ†’ {matches}") diff --git a/add_tailwind_blink_class.py b/add_tailwind_blink_class.py deleted file mode 100644 index 2b6c095d70..0000000000 --- a/add_tailwind_blink_class.py +++ /dev/null @@ -1,27 +0,0 @@ -import re - -# Read the main.css file -with open('ui/desktop/src/styles/main.css', 'r') as f: - content = f.read() - -print("Adding Tailwind animate-blink utility class...") - -# Find the @theme inline section and add the animation -theme_inline_section = '''@theme inline { - --ease-g2: cubic-bezier(0.55, 0, 1, 0.45);''' - -new_theme_inline_section = '''@theme inline { - --ease-g2: cubic-bezier(0.55, 0, 1, 0.45); - - --animate-blink: blink 1s step-end infinite;''' - -content = content.replace(theme_inline_section, new_theme_inline_section) - -# Write the modified content back -with open('ui/desktop/src/styles/main.css', 'w') as f: - f.write(content) - -print("โœ… Added animate-blink utility class to Tailwind theme") -print(" - Uses the blink keyframe with 1s duration") -print(" - step-end timing for sharp on/off transitions") -print(" - infinite loop for continuous blinking") diff --git a/add_visible_text_selection.py b/add_visible_text_selection.py deleted file mode 100644 index 446150357b..0000000000 --- a/add_visible_text_selection.py +++ /dev/null @@ -1,105 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Adding visible blue text selection highlight...") - -# Add selection styling to the hidden textarea -old_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.01, // Nearly invisible but still selectable - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'transparent', // Hide text but keep selection - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - }}''' - -new_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.01, // Nearly invisible but still selectable - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'transparent', // Hide text but keep selection - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - }} - className="absolute inset-0 w-full h-full resize-none selection:bg-blue-500 selection:text-white"''' - -content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -# Also add CSS to the main.css file for better selection styling -with open('ui/desktop/src/styles/main.css', 'r') as f: - css_content = f.read() - -# Add selection styling at the end of the file -selection_css = ''' -/* Text selection styling for RichChatInput */ -.rich-text-input textarea::selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} - -.rich-text-input textarea::-moz-selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} - -/* Global selection styling for better visibility */ -::selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} - -::-moz-selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} -''' - -if '/* Text selection styling for RichChatInput */' not in css_content: - css_content += selection_css - - with open('ui/desktop/src/styles/main.css', 'w') as f: - f.write(css_content) - - print("โœ… Added selection CSS to main.css") - -# Also add a wrapper class to the RichChatInput component -old_wrapper = ''' return ( -
''' - -new_wrapper = ''' return ( -
''' - -content = content.replace(old_wrapper, new_wrapper) - -# Write the final content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Added visible text selection highlighting:") -print(" - Added selection:bg-blue-500 selection:text-white to textarea") -print(" - Added CSS rules for ::selection styling") -print(" - Added rich-text-input wrapper class") -print(" - Selection should now be clearly visible with blue highlight") diff --git a/complete_mention_pill_rendering.py b/complete_mention_pill_rendering.py deleted file mode 100644 index 310d0df1f2..0000000000 --- a/complete_mention_pill_rendering.py +++ /dev/null @@ -1,181 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Completing mention pill rendering in RichChatInput...") - -# Find the section after we set up the matches and complete the processing logic -# We need to replace the old action-only processing with the new combined processing - -# First, let's find where the old processing logic ends and replace it -# Look for the section that processes beforeAction -old_processing_section = ''' console.log('โœ… Found action match:', match); - const beforeAction = value.slice(lastIndex, match.index); - const actionLabel = match[1]; - console.log('๐Ÿ“ Processing action:', { beforeAction, actionLabel, matchIndex: match.index }); - - // Add text before action with potential cursor - if (beforeAction) { - // Split text by cursor position to insert cursor at the right spot - let textWithCursor = []; - for (let i = 0; i < beforeAction.length; i++) { - if (isFocused && cursorPosition === currentPos) { - textWithCursor.push( - - ); - } - textWithCursor.push(beforeAction[i]); - currentPos++; - } - - parts.push( - - {textWithCursor} - - ); - } - - // Find matching action - const actionEntry = Object.entries(ACTION_MAP).find( - ([_, config]) => config.label === actionLabel - ); - - if (actionEntry) { - const [actionId, config] = actionEntry; - parts.push( - handleRemoveAction(actionLabel)} - /> - ); - } else { - // If no matching action, render as text - parts.push( - - {match[0]} - - ); - } - - currentPos += match[0].length; - lastIndex = match.index + match[0].length; - }''' - -new_processing_section = ''' console.log('โœ… Found match:', matchData); - - // Add text before this match with potential cursor - const beforeMatch = value.slice(lastIndex, index); - if (beforeMatch) { - let textWithCursor = []; - for (let i = 0; i < beforeMatch.length; i++) { - if (isFocused && cursorPosition === currentPos) { - textWithCursor.push( - - ); - } - textWithCursor.push(beforeMatch[i]); - currentPos++; - } - - parts.push( - - {textWithCursor} - - ); - } - - // Add cursor before match if needed - if (isFocused && cursorPosition === currentPos) { - parts.push( - - ); - } - - if (type === 'action') { - // Handle action pills - const actionLabel = content; - const actionEntry = Object.entries(ACTION_MAP).find( - ([_, config]) => config.label === actionLabel - ); - - if (actionEntry) { - const [actionId, config] = actionEntry; - parts.push( - handleRemoveAction(actionLabel)} - /> - ); - } else { - // If no matching action, render as text - parts.push( - - {match[0]} - - ); - } - } else if (type === 'mention') { - // Handle mention pills - const fileName = content; // filename without @ - const filePath = `@${fileName}`; // full mention text - - parts.push( - handleRemoveMention(fileName)} - /> - ); - } - - currentPos += length; - lastIndex = index + length; - }''' - -content = content.replace(old_processing_section, new_processing_section) - -# Add the handleRemoveMention function -old_handle_remove = ''' const handleRemoveAction = useCallback((actionLabel: string) => { - const actionText = `[${actionLabel}]`; - const newValue = value.replace(actionText, ''); - onChange(newValue); - }, [value, onChange]);''' - -new_handle_remove = ''' const handleRemoveAction = useCallback((actionLabel: string) => { - const actionText = `[${actionLabel}]`; - const newValue = value.replace(actionText, ''); - onChange(newValue); - }, [value, onChange]); - - const handleRemoveMention = useCallback((fileName: string) => { - const mentionText = `@${fileName}`; - const newValue = value.replace(mentionText, ''); - onChange(newValue); - }, [value, onChange]);''' - -content = content.replace(old_handle_remove, new_handle_remove) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Completed mention pill rendering:") -print(" - Updated processing logic to handle both actions and mentions") -print(" - Added MentionPill rendering for @filename patterns") -print(" - Added handleRemoveMention function for pill removal") -print(" - Mentions will now appear as green pills with file icon") diff --git a/comprehensive_action_fix.py b/comprehensive_action_fix.py deleted file mode 100644 index 88b84ec9a5..0000000000 --- a/comprehensive_action_fix.py +++ /dev/null @@ -1,98 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -print("Creating comprehensive fix for action pill population...") - -# 1. Clean up the RichChatInput onChange handler -# Find the current messy onChange and replace with clean version -old_onchange_pattern = r'onChange=\{\(newValue, cursorPos\) => \{[^}]*\}\}' -new_onchange = '''onChange={(newValue, cursorPos) => { - setDisplayValue(newValue); - updateValue(newValue); - debouncedSaveDraft(newValue); - setHasUserTyped(true); - - // Check for @ mention and / action triggers - if (cursorPos !== undefined) { - const syntheticTarget = { - getBoundingClientRect: () => textAreaRef.current?.getBoundingClientRect?.() || new DOMRect(), - selectionStart: cursorPos, - selectionEnd: cursorPos, - value: newValue, - }; - checkForMention(newValue, cursorPos, syntheticTarget as HTMLTextAreaElement); - } - }}''' - -# Use a more targeted replacement -lines = content.split('\n') -start_idx = -1 -end_idx = -1 -brace_count = 0 -in_onchange = False - -for i, line in enumerate(lines): - if 'onChange={(newValue, cursorPos) => {' in line: - start_idx = i - in_onchange = True - brace_count = line.count('{') - line.count('}') - elif in_onchange: - brace_count += line.count('{') - line.count('}') - if '}}' in line and brace_count <= 0: - end_idx = i - break - -if start_idx != -1 and end_idx != -1: - # Replace the onChange handler - new_lines = lines[:start_idx] + [' ' + new_onchange] + lines[end_idx + 1:] - content = '\n'.join(new_lines) - print(f"Fixed onChange handler (lines {start_idx}-{end_idx})") - -# 2. Ensure the actionPopover state has cursorPosition -if 'cursorPosition?: number;' not in content: - content = content.replace( - 'selectedIndex: number;\n }>({', - 'selectedIndex: number;\n cursorPosition?: number;\n }>({' - ) - content = content.replace( - 'selectedIndex: 0,\n });', - 'selectedIndex: 0,\n cursorPosition: 0,\n });' - ) - print("Added cursorPosition to actionPopover state") - -# 3. Make sure checkForMention sets cursorPosition when opening action popover -content = content.replace( - ''' setActionPopover({ - isOpen: true, - position: { - x: textAreaRect.left, - y: textAreaRect.top, - }, - selectedIndex: 0, - });''', - ''' setActionPopover({ - isOpen: true, - position: { - x: textAreaRect.left, - y: textAreaRect.top, - }, - selectedIndex: 0, - cursorPosition: cursorPosition, - });''' -) - -print("Updated checkForMention to set cursorPosition") - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("Comprehensive fix applied successfully!") -print("\nKey changes made:") -print("1. Cleaned up RichChatInput onChange handler") -print("2. Ensured actionPopover state includes cursorPosition") -print("3. Updated checkForMention to pass cursorPosition to actionPopover") -print("4. handleActionSelect should now work correctly with proper cursor position") diff --git a/create_mention_pill_component.py b/create_mention_pill_component.py deleted file mode 100644 index e076fdf9e0..0000000000 --- a/create_mention_pill_component.py +++ /dev/null @@ -1,67 +0,0 @@ -# Create MentionPill component similar to ActionPill -mention_pill_content = '''import React from 'react'; -import { X, File } from 'lucide-react'; - -interface MentionPillProps { - fileName: string; - filePath: string; - onRemove?: () => void; // Optional for read-only pills in messages - variant?: 'default' | 'message'; // Different styles for input vs message display - size?: 'sm' | 'md'; -} - -export const MentionPill: React.FC = ({ - fileName, - filePath, - onRemove, - variant = 'default', - size = 'sm' -}) => { - const baseClasses = "inline-flex items-center gap-1.5 font-medium border rounded-full"; - - const variantClasses = { - default: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700", - message: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700" - }; - - const sizeClasses = { - sm: "px-2 py-1 text-xs", - md: "px-3 py-1.5 text-sm" - }; - - return ( -
- - - {fileName} - - {onRemove && ( - - )} -
- ); -}; - -export default MentionPill; -''' - -# Write the MentionPill component -with open('ui/desktop/src/components/MentionPill.tsx', 'w') as f: - f.write(mention_pill_content) - -print("โœ… Created MentionPill component:") -print(" - Similar structure to ActionPill") -print(" - Uses green colors to differentiate from actions (blue)") -print(" - Shows File icon and filename") -print(" - Tooltip shows full file path") -print(" - Supports removal and different variants") diff --git a/debug_action_flow.py b/debug_action_flow.py deleted file mode 100644 index df330d8a4e..0000000000 --- a/debug_action_flow.py +++ /dev/null @@ -1,75 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Add debugging to handleActionSelect function -old_function_pattern = r' const handleActionSelect = \(actionId: string\) => \{[^}]*console\.log\([^)]*\);\s*setActionPopover[^}]*\};' - -new_function = ''' const handleActionSelect = (actionId: string) => { - console.log('๐ŸŽฏ handleActionSelect called with:', actionId); - const actionInfo = getActionInfo(actionId); - console.log('๐Ÿ“‹ Action info:', actionInfo); - - // Get current cursor position from the actionPopover state - const currentValue = displayValue; - const cursorPosition = actionPopover.cursorPosition || 0; - console.log('๐Ÿ“ Current state:', { currentValue, cursorPosition, displayValue }); - - const beforeCursor = currentValue.slice(0, cursorPosition); - const afterCursor = currentValue.slice(cursorPosition); - const lastSlashIndex = beforeCursor.lastIndexOf('/'); - - console.log('๐Ÿ” Cursor analysis:', { beforeCursor, afterCursor, lastSlashIndex }); - - if (lastSlashIndex !== -1) { - const afterSlash = beforeCursor.slice(lastSlashIndex + 1); - console.log('โšก After slash:', afterSlash); - - if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) { - // Replace the /query with [Action] text - const beforeSlash = currentValue.slice(0, lastSlashIndex); - const actionText = `[${actionInfo.label}]`; - const newValue = beforeSlash + actionText + " " + afterCursor; - - console.log('๐Ÿ”„ Text replacement:', { - beforeSlash, - actionText, - afterCursor, - newValue, - oldValue: currentValue - }); - - setDisplayValue(newValue); - setValue(newValue); - - console.log('โœ… Values set, new text should be:', newValue); - - // Set cursor position after the action text and space - const newCursorPosition = lastSlashIndex + actionText.length + 1; - setTimeout(() => { - if (textAreaRef.current) { - textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition); - textAreaRef.current.focus(); - } - }, 0); - } else { - console.log('โŒ After slash contains space/newline, not replacing'); - } - } else { - console.log('โŒ No slash found in text before cursor'); - } - - console.log('๐ŸŽฏ Action selected:', actionId, 'at position:', cursorPosition); - setActionPopover(prev => ({ ...prev, isOpen: false })); - };''' - -# Find and replace the function using regex -content = re.sub(old_function_pattern, new_function, content, flags=re.DOTALL) - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("Added comprehensive debugging to handleActionSelect") diff --git a/debug_action_popover.py b/debug_action_popover.py deleted file mode 100644 index fbf613116c..0000000000 --- a/debug_action_popover.py +++ /dev/null @@ -1,61 +0,0 @@ -import re - -# Read the ActionPopover file -with open('ui/desktop/src/components/ActionPopover.tsx', 'r') as f: - content = f.read() - -# Add debugging to handleItemClick -old_handleItemClick = ''' const handleItemClick = (index: number) => { - onSelectedIndexChange(index); - onSelect(actions[index].id); - actions[index].action(); - onClose(); - };''' - -new_handleItemClick = ''' const handleItemClick = (index: number) => { - console.log('๐ŸŽฏ ActionPopover: handleItemClick called', { index, actionId: actions[index].id }); - console.log('๐Ÿ“‹ ActionPopover: onSelect function:', onSelect); - console.log('๐Ÿ”„ ActionPopover: About to call onSelect with:', actions[index].id); - - onSelectedIndexChange(index); - - // Call onSelect first - this should trigger handleActionSelect in ChatInput - onSelect(actions[index].id); - - console.log('โœ… ActionPopover: onSelect called successfully'); - - // Call the local action (just for logging) - actions[index].action(); - - console.log('๐Ÿšช ActionPopover: Closing popover'); - onClose(); - };''' - -content = content.replace(old_handleItemClick, new_handleItemClick) - -# Also add debugging to the selectAction method in useImperativeHandle -old_selectAction = ''' selectAction: (index: number) => { - if (actions[index]) { - onSelect(actions[index].id); - actions[index].action(); - onClose(); - } - },''' - -new_selectAction = ''' selectAction: (index: number) => { - console.log('โŒจ๏ธ ActionPopover: selectAction called via keyboard', { index, actionId: actions[index]?.id }); - if (actions[index]) { - console.log('๐Ÿ”„ ActionPopover: Calling onSelect from selectAction:', actions[index].id); - onSelect(actions[index].id); - actions[index].action(); - onClose(); - } - },''' - -content = content.replace(old_selectAction, new_selectAction) - -# Write the modified content back -with open('ui/desktop/src/components/ActionPopover.tsx', 'w') as f: - f.write(content) - -print("Added comprehensive debugging to ActionPopover") diff --git a/debug_richtextinput.py b/debug_richtextinput.py deleted file mode 100644 index d682b2d5b7..0000000000 --- a/debug_richtextinput.py +++ /dev/null @@ -1,97 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -# Add debugging to the renderContent function -# Find the while loop that processes actions -old_while_section = ''' while ((match = actionRegex.exec(value)) !== null) { - const beforeAction = value.slice(lastIndex, match.index); - const actionLabel = match[1]; - - // Add text before action with potential cursor - if (beforeAction) {''' - -new_while_section = ''' console.log('๐ŸŽจ RichChatInput renderContent called with value:', value); - console.log('๐Ÿ” Looking for action patterns with regex:', actionRegex); - - while ((match = actionRegex.exec(value)) !== null) { - console.log('โœ… Found action match:', match); - const beforeAction = value.slice(lastIndex, match.index); - const actionLabel = match[1]; - console.log('๐Ÿ“ Processing action:', { beforeAction, actionLabel, matchIndex: match.index }); - - // Add text before action with potential cursor - if (beforeAction) {''' - -content = content.replace(old_while_section, new_while_section) - -# Add debugging to the action pill creation -old_pill_creation = ''' // Add the action pill - addCursorIfNeeded(currentPos); - const actionInfo = ACTION_MAP[actionLabel.toLowerCase().replace(/\\s+/g, '-') as keyof typeof ACTION_MAP] || - { label: actionLabel, icon: }; - - parts.push( - handleRemoveAction(actionLabel)} - /> - );''' - -new_pill_creation = ''' // Add the action pill - addCursorIfNeeded(currentPos); - const actionInfo = ACTION_MAP[actionLabel.toLowerCase().replace(/\\s+/g, '-') as keyof typeof ACTION_MAP] || - { label: actionLabel, icon: }; - - console.log('๐Ÿท๏ธ Creating action pill:', { actionLabel, actionInfo }); - - parts.push( - handleRemoveAction(actionLabel)} - /> - ); - - console.log('โœ… Action pill added to parts array');''' - -content = content.replace(old_pill_creation, new_pill_creation) - -# Add debugging to the onChange handler -old_onchange = ''' const handleTextareaChange = useCallback((e: React.ChangeEvent) => { - const newValue = e.target.value; - const newCursorPos = e.target.selectionStart; - - console.log('RichChatInput: onChange', { newValue, newCursorPos }); - onChange(newValue, newCursorPos); - setCursorPosition(newCursorPos); - }, [onChange]);''' - -new_onchange = ''' const handleTextareaChange = useCallback((e: React.ChangeEvent) => { - const newValue = e.target.value; - const newCursorPos = e.target.selectionStart; - - console.log('๐Ÿ”„ RichChatInput: onChange', { newValue, newCursorPos }); - console.log('๐ŸŽจ Will trigger re-render with new value:', newValue); - onChange(newValue, newCursorPos); - setCursorPosition(newCursorPos); - }, [onChange]);''' - -content = content.replace(old_onchange, new_onchange) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("Added comprehensive debugging to RichChatInput") diff --git a/fix_action_popover_order.py b/fix_action_popover_order.py deleted file mode 100644 index 8c92ebb662..0000000000 --- a/fix_action_popover_order.py +++ /dev/null @@ -1,80 +0,0 @@ -import re - -# Read the ActionPopover file -with open('ui/desktop/src/components/ActionPopover.tsx', 'r') as f: - content = f.read() - -# Fix the order of operations in handleItemClick - onSelect should happen BEFORE onClose -old_handleItemClick = ''' const handleItemClick = (index: number) => { - console.log('๐ŸŽฏ ActionPopover: handleItemClick called', { index, actionId: actions[index].id }); - console.log('๐Ÿ“‹ ActionPopover: onSelect function:', onSelect); - console.log('๐Ÿ”„ ActionPopover: About to call onSelect with:', actions[index].id); - - onSelectedIndexChange(index); - - // Call onSelect first - this should trigger handleActionSelect in ChatInput - onSelect(actions[index].id); - - console.log('โœ… ActionPopover: onSelect called successfully'); - - // Call the local action (just for logging) - actions[index].action(); - - console.log('๐Ÿšช ActionPopover: Closing popover'); - onClose(); - };''' - -new_handleItemClick = ''' const handleItemClick = (index: number) => { - console.log('๐ŸŽฏ ActionPopover: handleItemClick called', { index, actionId: actions[index].id }); - console.log('๐Ÿ“‹ ActionPopover: onSelect function:', onSelect); - console.log('๐Ÿ”„ ActionPopover: About to call onSelect with:', actions[index].id); - - onSelectedIndexChange(index); - - // Call onSelect first - this should trigger handleActionSelect in ChatInput - onSelect(actions[index].id); - - console.log('โœ… ActionPopover: onSelect called successfully'); - - // Call the local action (just for logging) - actions[index].action(); - - // Close popover after a small delay to allow text replacement to complete - console.log('๐Ÿšช ActionPopover: Closing popover after delay'); - setTimeout(() => { - onClose(); - }, 10); - };''' - -content = content.replace(old_handleItemClick, new_handleItemClick) - -# Also fix the selectAction method -old_selectAction = ''' selectAction: (index: number) => { - console.log('โŒจ๏ธ ActionPopover: selectAction called via keyboard', { index, actionId: actions[index]?.id }); - if (actions[index]) { - console.log('๐Ÿ”„ ActionPopover: Calling onSelect from selectAction:', actions[index].id); - onSelect(actions[index].id); - actions[index].action(); - onClose(); - } - },''' - -new_selectAction = ''' selectAction: (index: number) => { - console.log('โŒจ๏ธ ActionPopover: selectAction called via keyboard', { index, actionId: actions[index]?.id }); - if (actions[index]) { - console.log('๐Ÿ”„ ActionPopover: Calling onSelect from selectAction:', actions[index].id); - onSelect(actions[index].id); - actions[index].action(); - setTimeout(() => { - onClose(); - }, 10); - } - },''' - -content = content.replace(old_selectAction, new_selectAction) - -# Write the modified content back -with open('ui/desktop/src/components/ActionPopover.tsx', 'w') as f: - f.write(content) - -print("Fixed ActionPopover to delay onClose() call") diff --git a/fix_action_popover_state.py b/fix_action_popover_state.py deleted file mode 100644 index 8fc01c7a0e..0000000000 --- a/fix_action_popover_state.py +++ /dev/null @@ -1,81 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Fix 1: Update actionPopover state to include cursorPosition -old_state = ''' const [actionPopover, setActionPopover] = useState<{ - isOpen: boolean; - position: { x: number; y: number }; - selectedIndex: number; - }>({ - isOpen: false, - position: { x: 0, y: 0 }, - selectedIndex: 0, - });''' - -new_state = ''' const [actionPopover, setActionPopover] = useState<{ - isOpen: boolean; - position: { x: number; y: number }; - selectedIndex: number; - cursorPosition?: number; - }>({ - isOpen: false, - position: { x: 0, y: 0 }, - selectedIndex: 0, - cursorPosition: 0, - });''' - -content = content.replace(old_state, new_state) - -# Fix 2: Update the checkForMention function to set cursorPosition when opening action popover -# Find the section where action popover is opened -old_action_open = ''' setActionPopover({ - isOpen: true, - position: { - x: textAreaRect.left, - y: textAreaRect.top, - }, - selectedIndex: 0, - });''' - -new_action_open = ''' setActionPopover({ - isOpen: true, - position: { - x: textAreaRect.left, - y: textAreaRect.top, - }, - selectedIndex: 0, - cursorPosition: cursorPosition, - });''' - -content = content.replace(old_action_open, new_action_open) - -# Fix 3: Update handleActionButtonClick to include cursorPosition -old_button_click = ''' setActionPopover({ - isOpen: true, - position: { - x: buttonRect.left, - y: buttonRect.top, - }, - selectedIndex: 0, - });''' - -new_button_click = ''' setActionPopover({ - isOpen: true, - position: { - x: buttonRect.left, - y: buttonRect.top, - }, - selectedIndex: 0, - cursorPosition: textAreaRef.current?.getBoundingClientRect ? 0 : 0, // Will be set by RichChatInput - });''' - -content = content.replace(old_button_click, new_button_click) - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("Fixed actionPopover state to include cursorPosition") diff --git a/fix_action_selection.py b/fix_action_selection.py deleted file mode 100644 index d3ca5cfcd4..0000000000 --- a/fix_action_selection.py +++ /dev/null @@ -1,90 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Find and replace the handleActionSelect function -old_function = ''' const handleActionSelect = (actionId: string) => { - const actionInfo = getActionInfo(actionId); - - // Replace / with [Action] text inline - const currentValue = displayValue; - const cursorPosition = 0; // RichChatInput handles cursor position internally - const beforeCursor = currentValue.slice(0, cursorPosition); - const lastSlashIndex = beforeCursor.lastIndexOf('/'); - - if (lastSlashIndex !== -1) { - const afterSlash = beforeCursor.slice(lastSlashIndex + 1); - if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) { - // Replace / with [Action] text - const beforeSlash = currentValue.slice(0, lastSlashIndex); - // Simplified approach for RichChatInput - const actionText = `[${actionInfo.label}]`; - const newValue = beforeSlash + actionText + " "; - - setDisplayValue(newValue); - setValue(newValue); - - // Track selected action for pill display - - - // Set cursor position after the action text - setTimeout(() => { - if (textAreaRef.current) { - // Cursor positioning handled by RichChatInput - // Focus handled by RichChatInput - } - }, 0); - } - } - - console.log('Action selected:', actionId); - setActionPopover(prev => ({ ...prev, isOpen: false })); - };''' - -new_function = ''' const handleActionSelect = (actionId: string) => { - const actionInfo = getActionInfo(actionId); - - // Get current cursor position from the RichChatInput - const currentValue = displayValue; - const cursorPosition = actionPopover.cursorPosition || 0; - const beforeCursor = currentValue.slice(0, cursorPosition); - const afterCursor = currentValue.slice(cursorPosition); - const lastSlashIndex = beforeCursor.lastIndexOf('/'); - - if (lastSlashIndex !== -1) { - const afterSlash = beforeCursor.slice(lastSlashIndex + 1); - // Check if we're still in the same "word" after the slash - if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) { - // Replace the /query with [Action] text - const beforeSlash = currentValue.slice(0, lastSlashIndex); - const actionText = `[${actionInfo.label}]`; - const newValue = beforeSlash + actionText + " " + afterCursor; - - setDisplayValue(newValue); - setValue(newValue); - - // Set cursor position after the action text and space - const newCursorPosition = lastSlashIndex + actionText.length + 1; - setTimeout(() => { - if (textAreaRef.current) { - textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition); - textAreaRef.current.focus(); - } - }, 0); - } - } - - console.log('Action selected:', actionId, 'at position:', cursorPosition); - setActionPopover(prev => ({ ...prev, isOpen: false })); - };''' - -# Replace the function -content = content.replace(old_function, new_function) - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("Fixed handleActionSelect function to properly handle cursor position and create action pills") diff --git a/fix_chatinput.py b/fix_chatinput.py deleted file mode 100644 index b726a75984..0000000000 --- a/fix_chatinput.py +++ /dev/null @@ -1,106 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# 1. Add RichTextInput import after ActionPill import -content = re.sub( - r'(import ActionPill from \'\.\/ActionPill\';)', - r'\1\nimport RichTextInput, { ActionData } from \'./RichTextInput\';', - content -) - -# 2. Replace selectedActions state with actions state - find the exact pattern -selectedactions_pattern = r' // Action pills for visual display\s*const \[selectedActions, setSelectedActions\] = useState>.*?\[\]\);' -content = re.sub( - selectedactions_pattern, - ' // Action pills for visual display\n const [actions, setActions] = useState([]);', - content, - flags=re.DOTALL -) - -# 3. Remove the Selected Actions Pills section completely -selected_pills_pattern = r'\s*\{\/\* Selected Actions Pills \*\/\}\s*\{selectedActions\.length > 0 && \(\s*
\s*Selected:<\/span>\s*\{selectedActions\.map\(\(action\) => \(\s* handleRemoveAction\(action\.id\)\}\s*\/>\s*\)\)\}\s*<\/div>\s*\)\}' -content = re.sub(selected_pills_pattern, '', content, flags=re.DOTALL) - -# 4. Replace all selectedActions with actions and setSelectedActions with setActions -content = content.replace('selectedActions', 'actions') -content = content.replace('setActions([]);', 'setActions([]);') # Fix double replacement - -# 5. Update handleActionSelect - find and replace the entire function -handle_action_select_old = r' const handleActionSelect = \(actionId: string\) => \{[^}]*\};' -handle_action_select_new = ''' const handleActionSelect = (actionId: string) => { - const actionInfo = getActionInfo(actionId); - - // Replace / with [Action] text inline - const currentValue = displayValue; - const cursorPosition = textAreaRef.current?.selectionStart || 0; - const beforeCursor = currentValue.slice(0, cursorPosition); - const lastSlashIndex = beforeCursor.lastIndexOf('/'); - - if (lastSlashIndex !== -1) { - const afterSlash = beforeCursor.slice(lastSlashIndex + 1); - if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) { - // Replace / with [Action] text - const beforeSlash = currentValue.slice(0, lastSlashIndex); - const afterCursor = currentValue.slice(cursorPosition); - const actionText = `[${actionInfo.label}]`; - const newValue = beforeSlash + actionText + afterCursor; - - setDisplayValue(newValue); - setValue(newValue); - - // Track action for pill display - const newAction: ActionData = { - id: Date.now().toString() + Math.random().toString(36).substr(2, 9), - actionId, - label: actionInfo.label, - icon: actionInfo.icon, - position: lastSlashIndex, - }; - - setActions(prev => [...prev, newAction]); - - // Set cursor position after the action text - setTimeout(() => { - if (textAreaRef.current) { - const newCursorPosition = lastSlashIndex + actionText.length; - textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition); - } - }, 0); - } - } - - console.log('Action selected:', actionId); - setActionPopover(prev => ({ ...prev, isOpen: false })); - };''' - -# Find the function more carefully -lines = content.split('\n') -start_idx = -1 -end_idx = -1 -brace_count = 0 -in_function = False - -for i, line in enumerate(lines): - if 'const handleActionSelect = (actionId: string) => {' in line: - start_idx = i - in_function = True - brace_count = line.count('{') - line.count('}') - elif in_function: - brace_count += line.count('{') - line.count('}') - if brace_count == 0: - end_idx = i - break - -if start_idx != -1 and end_idx != -1: - # Replace the function - new_lines = lines[:start_idx] + handle_action_select_new.split('\n') + lines[end_idx + 1:] - content = '\n'.join(new_lines) - -print("ChatInput.tsx updated successfully") - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) diff --git a/fix_correct_tailwind_classes.py b/fix_correct_tailwind_classes.py deleted file mode 100644 index dec0cc8ef4..0000000000 --- a/fix_correct_tailwind_classes.py +++ /dev/null @@ -1,34 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing Tailwind class names to match the CSS variables...") - -# Looking at the CSS, the correct classes should be: -# - text-text-default (maps to --color-text-default) -# - text-text-muted (maps to --color-text-muted) -# - border-text-default (maps to --color-text-default) - -# Fix 1: Change placeholder text class -old_placeholder_class = 'className="text-textMuted pointer-events-none select-none"' -new_placeholder_class = 'className="text-text-muted pointer-events-none select-none"' - -content = content.replace(old_placeholder_class, new_placeholder_class) - -# Fix 2: Change cursor border class -old_cursor_border = 'border-textDefault' -new_cursor_border = 'border-text-default' - -content = content.replace(old_cursor_border, new_cursor_border) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed Tailwind class names:") -print(" - Changed text-textMuted to text-text-muted") -print(" - Changed border-textDefault to border-text-default") -print(" - These should now map to the correct CSS variables") -print(" - Should work properly in both light and dark modes") diff --git a/fix_cursor_and_placeholder_styling.py b/fix_cursor_and_placeholder_styling.py deleted file mode 100644 index 4aab54a444..0000000000 --- a/fix_cursor_and_placeholder_styling.py +++ /dev/null @@ -1,34 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor and placeholder styling...") - -# Fix 1: Change cursor color from white to grey -old_cursor_1 = 'className="animate-pulse border-l border-textStandard h-4 inline-block"' -new_cursor_1 = 'className="animate-pulse border-l border-textSubtle h-4 inline-block"' - -content = content.replace(old_cursor_1, new_cursor_1) - -# Fix 2: Also fix the cursor at the end of renderContent -old_cursor_2 = '' -new_cursor_2 = '' - -content = content.replace(old_cursor_2, new_cursor_2) - -# Fix 3: Ensure placeholder text is using textPlaceholder (should already be correct) -# Check if it's already using the right class -if 'text-textPlaceholder' in content: - print("โœ… Placeholder text already using textPlaceholder class") -else: - print("โš ๏ธ Placeholder text class might need fixing") - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed cursor styling:") -print(" - Changed from border-textStandard (white) to border-textSubtle (grey)") -print("โœ… Placeholder text should already be subtle (text-textPlaceholder)") diff --git a/fix_cursor_blink_with_css.py b/fix_cursor_blink_with_css.py deleted file mode 100644 index ef96d4a989..0000000000 --- a/fix_cursor_blink_with_css.py +++ /dev/null @@ -1,29 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor blink by using inline styles instead of Tailwind class...") - -# Replace animate-blink with inline style -old_cursor_1 = 'className="animate-blink border-l-2 border-black h-4 inline-block"' -new_cursor_1 = 'className="border-l-2 border-black h-4 inline-block" style={{ animation: "blink 1s step-end infinite" }}' - -content = content.replace(old_cursor_1, new_cursor_1) - -# Also fix the other cursor instance -old_cursor_2 = '' -new_cursor_2 = '' - -content = content.replace(old_cursor_2, new_cursor_2) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed cursor blinking by using inline CSS animation") -print(" - Removed animate-blink class (not recognized by Tailwind)") -print(" - Added inline style: animation: 'blink 1s step-end infinite'") -print(" - Uses the @keyframes blink defined in main.css") -print(" - Should now blink properly!") diff --git a/fix_cursor_line_break_logic.py b/fix_cursor_line_break_logic.py deleted file mode 100644 index 3286bcc80e..0000000000 --- a/fix_cursor_line_break_logic.py +++ /dev/null @@ -1,112 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor positioning logic for line breaks...") - -# The issue is in how we're processing character by character -# We need to handle newlines properly and render text as continuous flow -# Let's rewrite the text processing logic - -old_text_processing = ''' // Add text before action with potential cursor - if (beforeAction) { - const textParts = []; - for (let i = 0; i < beforeAction.length; i++) { - const char = beforeAction[i]; - addCursorIfNeeded(currentPos); - textParts.push(char); - currentPos++; - } - - parts.push( - - {textParts} - - ); - }''' - -new_text_processing = ''' // Add text before action with potential cursor - if (beforeAction) { - // Split text by cursor position to insert cursor at the right spot - let textWithCursor = []; - for (let i = 0; i < beforeAction.length; i++) { - if (isFocused && cursorPosition === currentPos) { - textWithCursor.push( - - ); - } - textWithCursor.push(beforeAction[i]); - currentPos++; - } - - parts.push( - - {textWithCursor} - - ); - }''' - -content = content.replace(old_text_processing, new_text_processing) - -# Also fix the remaining text processing -old_remaining_processing = ''' // Add remaining text with potential cursor - const remainingText = value.slice(lastIndex); - if (remainingText) { - const textParts = []; - for (let i = 0; i < remainingText.length; i++) { - const char = remainingText[i]; - addCursorIfNeeded(currentPos); - textParts.push(char); - currentPos++; - } - - parts.push( - - {textParts} - - ); - }''' - -new_remaining_processing = ''' // Add remaining text with potential cursor - const remainingText = value.slice(lastIndex); - if (remainingText) { - let textWithCursor = []; - for (let i = 0; i < remainingText.length; i++) { - if (isFocused && cursorPosition === currentPos) { - textWithCursor.push( - - ); - } - textWithCursor.push(remainingText[i]); - currentPos++; - } - - parts.push( - - {textWithCursor} - - ); - }''' - -content = content.replace(old_remaining_processing, new_remaining_processing) - -# Remove the separate addCursorIfNeeded calls since we're handling it inline now -content = content.replace(' // Add cursor before action if needed\n addCursorIfNeeded(currentPos);', '') -content = content.replace(' // Add cursor at the end if needed\n addCursorIfNeeded(currentPos);', ''' // Add cursor at the end if needed - if (isFocused && cursorPosition === currentPos) { - parts.push( - - ); - }''') - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed cursor positioning logic:") -print(" - Integrated cursor rendering directly into text processing") -print(" - Cursor now appears inline with text characters") -print(" - Should handle line breaks properly") -print(" - Cursor stays at correct position within the text flow") diff --git a/fix_cursor_placeholder_order.py b/fix_cursor_placeholder_order.py deleted file mode 100644 index fdbb7ff652..0000000000 --- a/fix_cursor_placeholder_order.py +++ /dev/null @@ -1,48 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor position to appear before placeholder text...") - -# Find the placeholder rendering and fix the cursor positioning -old_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- - {placeholder} - - {isFocused && ( - - )} -
- ); - }''' - -new_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- {isFocused && ( - - )} - - {placeholder} - -
- ); - }''' - -content = content.replace(old_placeholder_render, new_placeholder_render) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed cursor and placeholder order:") -print(" - Moved cursor before placeholder text in the DOM") -print(" - Changed ml-0.5 to mr-0.5 (margin-right instead of margin-left)") -print(" - Cursor now appears at the beginning of the line") -print(" - Placeholder text appears after the cursor") diff --git a/fix_cursor_positioning.py b/fix_cursor_positioning.py deleted file mode 100644 index 36886ba0cc..0000000000 --- a/fix_cursor_positioning.py +++ /dev/null @@ -1,29 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor positioning to align with text...") - -# Fix 1: Update cursor styling to match text height and alignment -old_cursor_1 = 'className="border-l-2 border-black h-4 inline-block" style={{ animation: "blink 1s step-end infinite" }}' -new_cursor_1 = 'className="border-l-2 border-black inline-block" style={{ animation: "blink 1s step-end infinite", height: "1.2em", marginLeft: "1px" }}' - -content = content.replace(old_cursor_1, new_cursor_1) - -# Fix 2: Also fix the other cursor instance -old_cursor_2 = '' -new_cursor_2 = '' - -content = content.replace(old_cursor_2, new_cursor_2) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed cursor positioning:") -print(" - Removed fixed h-4 height") -print(" - Added height: '1.2em' to match text line height") -print(" - Added marginLeft: '1px' for better spacing from text") -print(" - Cursor should now align properly with text") diff --git a/fix_cursor_to_black_blinking.py b/fix_cursor_to_black_blinking.py deleted file mode 100644 index e3f47b238c..0000000000 --- a/fix_cursor_to_black_blinking.py +++ /dev/null @@ -1,33 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Making cursor black and blinking like a regular cursor...") - -# Fix 1: Change cursor color from grey to black and use proper blinking animation -old_cursor_1 = 'className="animate-pulse border-l border-textSubtle h-4 inline-block"' -new_cursor_1 = 'className="animate-blink border-l-2 border-black h-4 inline-block"' - -content = content.replace(old_cursor_1, new_cursor_1) - -# Fix 2: Also fix the cursor at the end of renderContent -old_cursor_2 = '' -new_cursor_2 = '' - -content = content.replace(old_cursor_2, new_cursor_2) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Updated cursor styling:") -print(" - Changed from border-textSubtle (grey) to border-black") -print(" - Changed from animate-pulse to animate-blink") -print(" - Made border thicker (border-l-2) for better visibility") -print(" - Now behaves like a regular text cursor") - -# Now we need to add the custom blink animation to the CSS -print("\n๐Ÿ“ Note: We need to add the animate-blink class to Tailwind config") -print(" This will make the cursor blink on/off like a regular text cursor") diff --git a/fix_cursor_vertical_alignment.py b/fix_cursor_vertical_alignment.py deleted file mode 100644 index 364860089a..0000000000 --- a/fix_cursor_vertical_alignment.py +++ /dev/null @@ -1,30 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor vertical alignment with text...") - -# Find all cursor instances and fix their styling -old_cursor_style = 'style={{ animation: "blink 1s step-end infinite", height: "1.2em", marginLeft: "1px" }}' -new_cursor_style = 'style={{ animation: "blink 1s step-end infinite", height: "1em", marginLeft: "1px", verticalAlign: "baseline" }}' - -content = content.replace(old_cursor_style, new_cursor_style) - -# Also need to ensure the cursor aligns with the text line height -# Let's also adjust the className to help with alignment -old_cursor_class = 'className="border-l-2 border-black inline-block"' -new_cursor_class = 'className="border-l-2 border-black inline-block align-baseline"' - -content = content.replace(old_cursor_class, new_cursor_class) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed cursor vertical alignment:") -print(" - Changed height from 1.2em to 1em (matches text height)") -print(" - Added verticalAlign: 'baseline' to align with text baseline") -print(" - Added align-baseline class for consistent alignment") -print(" - Cursor should now be centered with the text line") diff --git a/fix_dark_mode_cursor_and_text.py b/fix_dark_mode_cursor_and_text.py deleted file mode 100644 index 40bcb83e97..0000000000 --- a/fix_dark_mode_cursor_and_text.py +++ /dev/null @@ -1,33 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing dark mode cursor color and text color...") - -# Fix 1: Change cursor from black to theme-aware color -# Find all cursor instances and replace border-black with border-textDefault -old_cursor_class = 'className="border-l-2 border-black inline-block align-baseline absolute left-0"' -new_cursor_class = 'className="border-l-2 border-textDefault inline-block align-baseline absolute left-0"' - -content = content.replace(old_cursor_class, new_cursor_class) - -# Also fix other cursor instances in the text processing -content = content.replace('border-l-2 border-black inline-block', 'border-l-2 border-textDefault inline-block') - -# Fix 2: Change placeholder text color to match text-textMuted properly -old_placeholder_color = 'className="text-textMuted pointer-events-none select-none"' -new_placeholder_color = 'className="text-textMuted pointer-events-none select-none"' - -# The placeholder color is already correct, but let's make sure it's using the right class - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed dark mode styling:") -print(" - Changed cursor from border-black to border-textDefault") -print(" - Cursor will now be white in dark mode, black in light mode") -print(" - Placeholder text already uses text-textMuted which adapts to theme") -print(" - Both cursor and text should now work properly in dark mode") diff --git a/fix_import_issue.py b/fix_import_issue.py deleted file mode 100644 index 1ce1be42d3..0000000000 --- a/fix_import_issue.py +++ /dev/null @@ -1,38 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Fix the import - change from default import to named import -old_import = "import RichChatInput, { RichChatInputRef } from './RichChatInput';" -new_import = "import { RichChatInput, RichChatInputRef } from './RichChatInput';" - -content = content.replace(old_import, new_import) - -print("Fixed RichChatInput import to use named export") - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -# Also check if we need to fix the RichChatInput export -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - rich_content = f.read() - -# Make sure it has both named and default exports -if 'export default RichChatInput;' not in rich_content: - # Add default export if missing - rich_content = rich_content.replace( - 'RichChatInput.displayName = \'RichChatInput\';', - 'RichChatInput.displayName = \'RichChatInput\';\n\nexport default RichChatInput;' - ) - - with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(rich_content) - - print("Added default export to RichChatInput") -else: - print("RichChatInput already has default export") - -print("Import/export issue fixed!") diff --git a/fix_inline_message_display.py b/fix_inline_message_display.py deleted file mode 100644 index a33a409452..0000000000 --- a/fix_inline_message_display.py +++ /dev/null @@ -1,87 +0,0 @@ -import re - -# Read the MessageContent file -with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f: - content = f.read() - -print("Fixing MessageContent to display pills inline...") - -# Replace the entire return statement to fix inline display -old_return = ''' return ( -
- {parsedContent.map((part, index) => { - if (part.type === 'action' && part.actionId) { - const actionInfo = getActionInfo(part.actionId); - return ( - - ); - } else if (part.content.trim()) { - return ( - - ); - } - return null; - })} -
- );''' - -new_return = ''' return ( - - {parsedContent.map((part, index) => { - if (part.type === 'action' && part.actionId) { - const actionInfo = getActionInfo(part.actionId); - return ( - - ); - } else if (part.content.trim()) { - return ( - $1') - .replace(/\*(.*?)\*/g, '$1') - .replace(/`(.*?)`/g, '$1') - .replace(/\n/g, '
') - }} - /> - ); - } - return null; - })} -
- );''' - -content = content.replace(old_return, new_return) - -# Write the modified content back -with open('ui/desktop/src/components/MessageContent.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed MessageContent to display pills inline with text") -print("Key changes:") -print("1. Changed container from
to with inline-flex") -print("2. Replaced MarkdownContent with inline and basic HTML formatting") -print("3. Used items-baseline for better text alignment") -print("4. Applied inline styling to prevent line breaks") diff --git a/fix_input_spacing.py b/fix_input_spacing.py deleted file mode 100644 index 56110f5a49..0000000000 --- a/fix_input_spacing.py +++ /dev/null @@ -1,110 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing input spacing to match original ChatInput padding...") - -# The original ChatInput has: px-3 pt-3 pb-1.5 pr-20 text-sm -# That translates to: padding: 12px 80px 6px 12px; font-size: 14px; - -# Update both the hidden textarea and visual display to have proper padding -old_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.15, // Slightly more visible for selection - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'rgba(59, 130, 246, 0.2)', // Slightly more visible blue text - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - fontFamily: 'Cash Sans, sans-serif', // Match exact font - fontSize: '0.875rem', // Match text-sm (14px) - lineHeight: '1.5', // Match leading-relaxed - padding: '0', // No padding to match visual display - margin: '0', - boxSizing: 'border-box', - whiteSpace: 'pre-wrap', // Match visual display - wordWrap: 'break-word', - }}''' - -new_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.15, // Slightly more visible for selection - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'rgba(59, 130, 246, 0.2)', // Slightly more visible blue text - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - fontFamily: 'Cash Sans, sans-serif', // Match exact font - fontSize: '0.875rem', // Match text-sm (14px) - lineHeight: '1.5', // Match leading-relaxed - padding: '12px 80px 6px 12px', // Match original: px-3 pt-3 pb-1.5 pr-20 - margin: '0', - boxSizing: 'border-box', - whiteSpace: 'pre-wrap', // Match visual display - wordWrap: 'break-word', - }}''' - -content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style) - -# Update the visual display to have matching padding -old_visual_display_style = ''' style={{ - ...style, - minHeight: `${rows * 1.5}em`, - zIndex: 1, // Lower z-index, behind textarea - pointerEvents: 'none', // Don't interfere with text selection - userSelect: 'none', // Prevent selection on visual layer - WebkitUserSelect: 'none', - fontFamily: 'Cash Sans, sans-serif', // Match textarea font - fontSize: '0.875rem', // Match textarea size - lineHeight: '1.5', // Match textarea line height - padding: '0', // Match textarea padding - margin: '0', - whiteSpace: 'pre-wrap', // Match textarea - wordWrap: 'break-word', - }}''' - -new_visual_display_style = ''' style={{ - ...style, - minHeight: `${rows * 1.5}em`, - zIndex: 1, // Lower z-index, behind textarea - pointerEvents: 'none', // Don't interfere with text selection - userSelect: 'none', // Prevent selection on visual layer - WebkitUserSelect: 'none', - fontFamily: 'Cash Sans, sans-serif', // Match textarea font - fontSize: '0.875rem', // Match textarea size - lineHeight: '1.5', // Match textarea line height - padding: '12px 80px 6px 12px', // Match original: px-3 pt-3 pb-1.5 pr-20 - margin: '0', - whiteSpace: 'pre-wrap', // Match textarea - wordWrap: 'break-word', - }}''' - -content = content.replace(old_visual_display_style, new_visual_display_style) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed input spacing:") -print(" - Added proper padding: 12px 80px 6px 12px (px-3 pt-3 pb-1.5 pr-20)") -print(" - Left padding: 12px (px-3)") -print(" - Top padding: 12px (pt-3)") -print(" - Bottom padding: 6px (pb-1.5)") -print(" - Right padding: 80px (pr-20) - space for action buttons") -print(" - Both layers now have matching spacing") diff --git a/fix_mention_file_select_properly.py b/fix_mention_file_select_properly.py deleted file mode 100644 index de18ae9519..0000000000 --- a/fix_mention_file_select_properly.py +++ /dev/null @@ -1,78 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing handleMentionFileSelect to create @filename format...") - -# Find the current handleMentionFileSelect function and replace it -old_function = ''' const handleMentionFileSelect = (filePath: string) => { - // Replace the @ mention with the file path - const beforeMention = displayValue.slice(0, mentionPopover.mentionStart); - const afterMention = displayValue.slice( - mentionPopover.mentionStart + 1 + mentionPopover.query.length - ); - const newValue = `${beforeMention}${filePath}${afterMention}`; - - setDisplayValue(newValue); - setValue(newValue); - setMentionPopover((prev) => ({ ...prev, isOpen: false })); - textAreaRef.current?.focus(); - - // Set cursor position after the inserted file path - setTimeout(() => { - if (textAreaRef.current) { - // Cursor positioning handled by RichChatInput - // Focus handled by RichChatInput - } - }, 0); - };''' - -new_function = ''' const handleMentionFileSelect = (filePath: string) => { - console.log('๐Ÿ“ handleMentionFileSelect called with:', filePath); - - // Extract just the filename from the full path for the pill - const fileName = filePath.split('/').pop() || filePath; - console.log('๐Ÿ“ Extracted filename:', fileName); - - // Create @filename format for pill detection - const mentionText = `@${fileName}`; - console.log('๐Ÿ“ Creating mention text:', mentionText); - - // Replace the @ mention with @filename format - const beforeMention = displayValue.slice(0, mentionPopover.mentionStart); - const afterMention = displayValue.slice( - mentionPopover.mentionStart + 1 + mentionPopover.query.length - ); - const newValue = `${beforeMention}${mentionText} ${afterMention}`; - - console.log('๐Ÿ“ New value will be:', newValue); - - setDisplayValue(newValue); - setValue(newValue); - setMentionPopover((prev) => ({ ...prev, isOpen: false })); - textAreaRef.current?.focus(); - - // Set cursor position after the inserted mention and space - const newCursorPosition = beforeMention.length + mentionText.length + 1; - setTimeout(() => { - if (textAreaRef.current) { - textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition); - textAreaRef.current.focus(); - } - }, 0); - };''' - -content = content.replace(old_function, new_function) - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed handleMentionFileSelect function:") -print(" - Now extracts filename from full path") -print(" - Creates @filename format instead of full path") -print(" - Adds space after mention for better UX") -print(" - Added comprehensive debugging logs") -print(" - Should now create text that matches the mention regex") diff --git a/fix_message_pill_line_breaks.py b/fix_message_pill_line_breaks.py deleted file mode 100644 index 140ceba720..0000000000 --- a/fix_message_pill_line_breaks.py +++ /dev/null @@ -1,28 +0,0 @@ -import re - -# Read the MessageContent file -with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f: - content = f.read() - -print("Fixing document pill line breaks in message display...") - -# The issue is the same as before - using flex layout causes pills to break lines -# Change from flex to inline layout like we did for the input - -old_container = ''' return ( - ''' - -new_container = ''' return ( - ''' - -content = content.replace(old_container, new_container) - -# Write the modified content back -with open('ui/desktop/src/components/MessageContent.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed message pill line breaks:") -print(" - Changed from inline-flex flex-wrap to inline") -print(" - Removed flex layout that was causing line breaks") -print(" - Pills should now flow inline with text in messages") -print(" - Same fix as applied to input field earlier") diff --git a/fix_multiline_cursor_positioning.py b/fix_multiline_cursor_positioning.py deleted file mode 100644 index 0d9c40540b..0000000000 --- a/fix_multiline_cursor_positioning.py +++ /dev/null @@ -1,48 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing cursor positioning for multi-line text...") - -# The issue is with the container layout. We need to change from flex to inline layout -# Find the return statement with the flex container -old_container = ''' return ( -
- {parts.length > 0 ? parts : ( - isFocused && ( - - ) - )} -
- );''' - -new_container = ''' return ( -
- {parts.length > 0 ? parts : ( - isFocused && ( - - ) - )} -
- );''' - -content = content.replace(old_container, new_container) - -# Also need to fix how text parts are rendered to be truly inline -# Find the text rendering sections and make sure they're inline -old_text_span = 'className="whitespace-pre-wrap"' -new_text_span = 'className="inline whitespace-pre-wrap"' - -content = content.replace(old_text_span, new_text_span) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed multi-line cursor positioning:") -print(" - Changed container from flex to whitespace-pre-wrap") -print(" - Added leading-relaxed for better line height") -print(" - Made text spans explicitly inline") -print(" - Cursor should now stay in correct position on line breaks") diff --git a/fix_placeholder_behavior.py b/fix_placeholder_behavior.py deleted file mode 100644 index 12cb6b2504..0000000000 --- a/fix_placeholder_behavior.py +++ /dev/null @@ -1,45 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing placeholder behavior to stay visible when focused...") - -# Find the renderContent function and fix the placeholder logic -old_placeholder_logic = ''' const renderContent = useCallback(() => { - if (!value.trim() && !isFocused) { - return ( - - {placeholder} - - ); - }''' - -new_placeholder_logic = ''' const renderContent = useCallback(() => { - // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- - {placeholder} - - {isFocused && ( - - )} -
- ); - }''' - -content = content.replace(old_placeholder_logic, new_placeholder_logic) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed placeholder behavior:") -print(" - Changed from text-textPlaceholder to text-textSubtle (matches icon color)") -print(" - Placeholder now stays visible when input is focused") -print(" - Only disappears when user actually types text") -print(" - Cursor appears alongside placeholder when focused") -print(" - Uses absolute positioning to overlay cursor on placeholder") diff --git a/fix_placeholder_color_lighter.py b/fix_placeholder_color_lighter.py deleted file mode 100644 index a86b3c0b6a..0000000000 --- a/fix_placeholder_color_lighter.py +++ /dev/null @@ -1,22 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Changing placeholder color back to lighter original color...") - -# Find the placeholder text and change it back to the original lighter color -old_placeholder_color = 'className="text-textSubtle pointer-events-none select-none"' -new_placeholder_color = 'className="text-textPlaceholder pointer-events-none select-none"' - -content = content.replace(old_placeholder_color, new_placeholder_color) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed placeholder color:") -print(" - Changed from text-textSubtle (darker grey) back to text-textPlaceholder (lighter grey)") -print(" - Now uses the same light color as the original empty text") -print(" - Should be more subtle and less prominent") diff --git a/fix_placeholder_color_medium.py b/fix_placeholder_color_medium.py deleted file mode 100644 index 9e457b7eb1..0000000000 --- a/fix_placeholder_color_medium.py +++ /dev/null @@ -1,22 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Changing placeholder to a medium grey color...") - -# Find the placeholder text and change it to text-muted (neutral-400) -old_placeholder_color = 'className="text-textPlaceholder pointer-events-none select-none"' -new_placeholder_color = 'className="text-textMuted pointer-events-none select-none"' - -content = content.replace(old_placeholder_color, new_placeholder_color) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed placeholder color:") -print(" - Changed from text-textPlaceholder (very light) to text-textMuted (medium grey)") -print(" - Uses --color-neutral-400 which should be more visible") -print(" - Should be a good balance between subtle and readable") diff --git a/fix_placeholder_positioning.py b/fix_placeholder_positioning.py deleted file mode 100644 index b94daa0ee5..0000000000 --- a/fix_placeholder_positioning.py +++ /dev/null @@ -1,49 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing placeholder positioning and visibility...") - -# Find the placeholder rendering logic and fix the positioning -old_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- - {placeholder} - - {isFocused && ( - - )} -
- ); - }''' - -new_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- - {placeholder} - - {isFocused && ( - - )} -
- ); - }''' - -content = content.replace(old_placeholder_render, new_placeholder_render) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed placeholder positioning:") -print(" - Removed absolute positioning that was causing cutoff") -print(" - Added min-h-[1.5em] to ensure proper container height") -print(" - Added flex items-center for proper vertical alignment") -print(" - Used ml-0.5 instead of marginLeft for cursor spacing") -print(" - Placeholder should now be visible and properly positioned") diff --git a/fix_placeholder_text_shift.py b/fix_placeholder_text_shift.py deleted file mode 100644 index 1f5c6c06b1..0000000000 --- a/fix_placeholder_text_shift.py +++ /dev/null @@ -1,57 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing placeholder text shift when cursor appears...") - -# Find the placeholder rendering and fix it to prevent text shifting -old_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- {isFocused && ( - - )} - - {placeholder} - -
- ); - }''' - -new_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state) - if (!value.trim()) { - return ( -
- - {placeholder} - - {isFocused && ( - - )} -
- ); - }''' - -content = content.replace(old_placeholder_render, new_placeholder_render) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed placeholder text shifting:") -print(" - Made cursor absolutely positioned so it doesn't affect layout") -print(" - Added left-0 to position cursor at the start") -print(" - Added top: 50% and transform: translateY(-50%) for vertical centering") -print(" - Placeholder text now stays in exact same position when cursor appears") diff --git a/fix_regex_error.py b/fix_regex_error.py deleted file mode 100644 index f952564365..0000000000 --- a/fix_regex_error.py +++ /dev/null @@ -1,34 +0,0 @@ -import re - -# Read the MessageContent file -with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f: - content = f.read() - -print("Fixing regex syntax error in MessageContent...") - -# Fix the broken regex - the newline replacement got split -old_broken_html = ''' dangerouslySetInnerHTML={{ - __html: part.content - .replace(/\*\*(.*?)\*\*/g, '$1') - .replace(/\*(.*?)\*/g, '$1') - .replace(/`(.*?)`/g, '$1') - .replace(/ -/g, '
') - }}''' - -new_fixed_html = ''' dangerouslySetInnerHTML={{ - __html: part.content - .replace(/\*\*(.*?)\*\*/g, '$1') - .replace(/\*(.*?)\*/g, '$1') - .replace(/`(.*?)`/g, '$1') - .replace(/\\n/g, '
') - }}''' - -content = content.replace(old_broken_html, new_fixed_html) - -# Write the modified content back -with open('ui/desktop/src/components/MessageContent.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed regex syntax error") -print("Changed .replace(/\\n/g, '
') - newline regex was broken across lines") diff --git a/fix_richtextinput_integration.py b/fix_richtextinput_integration.py deleted file mode 100644 index dcbf492793..0000000000 --- a/fix_richtextinput_integration.py +++ /dev/null @@ -1,43 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Find the RichChatInput onChange handler and update it to handle cursor position -old_onchange = ''' onChange={(newValue, cursorPos) => { - setDisplayValue(newValue); - updateValue(newValue); - debouncedSaveDraft(newValue); - setHasUserTyped(true); - - // Check for mention/action triggers with the new cursor position - if (cursorPos !== undefined) { - checkForMention(newValue, cursorPos, textAreaRef.current!); - } - }}''' - -new_onchange = ''' onChange={(newValue, cursorPos) => { - setDisplayValue(newValue); - updateValue(newValue); - debouncedSaveDraft(newValue); - setHasUserTyped(true); - - // Check for mention/action triggers with the new cursor position - if (cursorPos !== undefined) { - checkForMention(newValue, cursorPos, { - getBoundingClientRect: () => textAreaRef.current?.getBoundingClientRect?.() || new DOMRect(), - selectionStart: cursorPos, - selectionEnd: cursorPos, - value: newValue, - } as HTMLTextAreaElement); - } - }}''' - -content = content.replace(old_onchange, new_onchange) - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("Fixed RichChatInput onChange integration with cursor position handling") diff --git a/fix_richtextinput_processing_loop.py b/fix_richtextinput_processing_loop.py deleted file mode 100644 index 71f257a667..0000000000 --- a/fix_richtextinput_processing_loop.py +++ /dev/null @@ -1,169 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing RichChatInput processing loop to handle both actions and mentions...") - -# Find the entire processing loop section and replace it -# Look for the section that starts with "Process all matches in order" -old_processing_section = ''' // Process all matches in order - for (const matchData of allMatches) { - const { type, match, index, length, content } = matchData; - console.log('โœ… Found action match:', match); - const beforeAction = value.slice(lastIndex, match.index); - const actionLabel = match[1]; - console.log('๐Ÿ“ Processing action:', { beforeAction, actionLabel, matchIndex: match.index }); - - // Add text before action with potential cursor - if (beforeAction) { - // Split text by cursor position to insert cursor at the right spot - let textWithCursor = []; - for (let i = 0; i < beforeAction.length; i++) { - if (isFocused && cursorPosition === currentPos) { - textWithCursor.push( - - ); - } - textWithCursor.push(beforeAction[i]); - currentPos++; - } - - parts.push( - - {textWithCursor} - - ); - } - - - - // Find matching action - const actionEntry = Object.entries(ACTION_MAP).find( - ([_, config]) => config.label === actionLabel - ); - - if (actionEntry) { - const [actionId, config] = actionEntry; - parts.push( - handleRemoveAction(actionLabel)} - /> - ); - } else { - // If no matching action, render as text - parts.push( - - {match[0]} - - ); - } - - currentPos += match[0].length; - lastIndex = match.index + match[0].length; - }''' - -new_processing_section = ''' // Process all matches in order - for (const matchData of allMatches) { - const { type, match, index, length, content } = matchData; - console.log('โœ… Found match:', { type, content, index }); - - // Add text before this match with potential cursor - const beforeMatch = value.slice(lastIndex, index); - if (beforeMatch) { - let textWithCursor = []; - for (let i = 0; i < beforeMatch.length; i++) { - if (isFocused && cursorPosition === currentPos) { - textWithCursor.push( - - ); - } - textWithCursor.push(beforeMatch[i]); - currentPos++; - } - - parts.push( - - {textWithCursor} - - ); - } - - // Add cursor before match if needed - if (isFocused && cursorPosition === currentPos) { - parts.push( - - ); - } - - if (type === 'action') { - // Handle action pills - const actionLabel = content; - const actionEntry = Object.entries(ACTION_MAP).find( - ([_, config]) => config.label === actionLabel - ); - - console.log('๐Ÿท๏ธ Creating action pill:', { actionLabel, actionEntry }); - - if (actionEntry) { - const [actionId, config] = actionEntry; - parts.push( - handleRemoveAction(actionLabel)} - /> - ); - } else { - // If no matching action, render as text - parts.push( - - {match[0]} - - ); - } - } else if (type === 'mention') { - // Handle mention pills - const fileName = content; // filename without @ - const filePath = `@${fileName}`; // full mention text - - console.log('๐Ÿ“ Creating mention pill:', { fileName, filePath }); - - parts.push( - handleRemoveMention(fileName)} - /> - ); - } - - currentPos += length; - lastIndex = index + length; - }''' - -content = content.replace(old_processing_section, new_processing_section) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed RichChatInput processing loop:") -print(" - Updated to use new combined action/mention processing") -print(" - Added proper mention pill creation") -print(" - Added debugging logs for both types") -print(" - Should now render @filename as green pills") diff --git a/fix_selection_alignment.py b/fix_selection_alignment.py deleted file mode 100644 index 87b591eca9..0000000000 --- a/fix_selection_alignment.py +++ /dev/null @@ -1,118 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing selection alignment - making hidden textarea match visual display exactly...") - -# The issue is that the hidden textarea and visual display have different positioning/padding -# We need to make them align perfectly - -# Update the hidden textarea to match the visual display exactly -old_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.1, // More visible for selection - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'rgba(59, 130, 246, 0.1)', // Very light blue text - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - fontFamily: 'inherit', - fontSize: 'inherit', - lineHeight: 'inherit', - padding: 'inherit', - }}''' - -new_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.15, // Slightly more visible for selection - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'rgba(59, 130, 246, 0.2)', // Slightly more visible blue text - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - fontFamily: 'Cash Sans, sans-serif', // Match exact font - fontSize: '0.875rem', // Match text-sm (14px) - lineHeight: '1.5', // Match leading-relaxed - padding: '0', // No padding to match visual display - margin: '0', - boxSizing: 'border-box', - whiteSpace: 'pre-wrap', // Match visual display - wordWrap: 'break-word', - }}''' - -content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style) - -# Also need to make sure the visual display has consistent styling -old_visual_display = ''' {/* Visual display with action pills and cursor */} -
- {renderContent()} -
''' - -new_visual_display = ''' {/* Visual display with action pills and cursor */} -
- {renderContent()} -
''' - -content = content.replace(old_visual_display, new_visual_display) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed selection alignment:") -print(" - Matched font family, size, and line height exactly") -print(" - Removed padding/margin differences") -print(" - Added consistent white-space and word-wrap") -print(" - Selection should now align perfectly with visual text") -print(" - No more 'holographic' offset effect") diff --git a/fix_selection_visibility.py b/fix_selection_visibility.py deleted file mode 100644 index c1d1cca575..0000000000 --- a/fix_selection_visibility.py +++ /dev/null @@ -1,124 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing selection visibility to show over visual content...") - -# The issue is that selection is happening on the hidden textarea but we need it visible over the visual layer -# Let's make the hidden textarea slightly more visible and add a selection overlay - -# Update the hidden textarea to be slightly more visible during selection -old_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.01, // Nearly invisible but still selectable - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'transparent', // Hide text but keep selection - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - }} - className="absolute inset-0 w-full h-full resize-none selection:bg-blue-500 selection:text-white"''' - -new_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.1, // More visible for selection - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'rgba(59, 130, 246, 0.1)', // Very light blue text - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - fontFamily: 'inherit', - fontSize: 'inherit', - lineHeight: 'inherit', - padding: 'inherit', - }} - className="absolute inset-0 w-full h-full resize-none selection:bg-blue-500 selection:text-white"''' - -content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style) - -# Also update the CSS to make selection more prominent -css_update = ''' -/* Enhanced text selection styling */ -.rich-text-input textarea::selection { - background-color: #3b82f6 !important; /* Blue-500 with !important */ - color: white !important; - opacity: 1 !important; -} - -.rich-text-input textarea::-moz-selection { - background-color: #3b82f6 !important; /* Blue-500 with !important */ - color: white !important; - opacity: 1 !important; -} - -/* Make sure selection is visible over visual content */ -.rich-text-input { - position: relative; -} - -.rich-text-input textarea { - mix-blend-mode: multiply; /* Blend with background for better visibility */ -} -''' - -# Update the main.css file -with open('ui/desktop/src/styles/main.css', 'r') as f: - css_content = f.read() - -# Replace the existing selection CSS with enhanced version -old_selection_css = '''/* Text selection styling for RichChatInput */ -.rich-text-input textarea::selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} - -.rich-text-input textarea::-moz-selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} - -/* Global selection styling for better visibility */ -::selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -} - -::-moz-selection { - background-color: #3b82f6; /* Blue-500 */ - color: white; -}''' - -if old_selection_css in css_content: - css_content = css_content.replace(old_selection_css, css_update) -else: - css_content += css_update - -with open('ui/desktop/src/styles/main.css', 'w') as f: - f.write(css_content) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Enhanced selection visibility:") -print(" - Increased textarea opacity to 0.1 for better selection visibility") -print(" - Added light blue text color for better contrast") -print(" - Added !important to selection CSS rules") -print(" - Added mix-blend-mode for better visual blending") -print(" - Selection should now be much more visible") diff --git a/fix_text_selection_behavior.py b/fix_text_selection_behavior.py deleted file mode 100644 index f2e9ce7fb9..0000000000 --- a/fix_text_selection_behavior.py +++ /dev/null @@ -1,133 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing text selection behavior to work like a normal text input...") - -# The main issue is that we need to make the hidden textarea more accessible -# and reduce interference from the visual display layer - -# First, let's update the hidden textarea to be more interactive -old_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.01, // Nearly invisible but still selectable - zIndex: 1, - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'transparent', // Hide text but keep selection - caretColor: 'transparent', // Hide caret (we show our own) - }}''' - -new_hidden_textarea_style = ''' style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.01, // Nearly invisible but still selectable - zIndex: 2, // Higher z-index to capture mouse events - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'transparent', // Hide text but keep selection - caretColor: 'transparent', // Hide caret (we show our own) - pointerEvents: 'auto', // Ensure it can receive mouse events - }}''' - -content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style) - -# Update the visual display to have lower z-index and not interfere with selection -old_visual_display = ''' {/* Visual display with action pills and cursor */} -
- {renderContent()} -
''' - -new_visual_display = ''' {/* Visual display with action pills and cursor */} -
- {renderContent()} -
''' - -content = content.replace(old_visual_display, new_visual_display) - -# Remove the handleDisplayClick since we're not using it anymore -old_handle_display_click = ''' const handleDisplayClick = useCallback((e: React.MouseEvent) => { - // Don't focus if clicking on an action pill - if ((e.target as Element).closest('.action-pill-wrapper')) { - return; - } - - // Focus the hidden textarea for text selection - if (hiddenTextareaRef.current) { - hiddenTextareaRef.current.focus(); - - // For double/triple click, select text appropriately - if (e.detail === 2) { - // Double click - select word (let browser handle this) - setTimeout(() => { - if (hiddenTextareaRef.current) { - hiddenTextareaRef.current.select(); - } - }, 0); - } else if (e.detail === 3) { - // Triple click - select all - setTimeout(() => { - if (hiddenTextareaRef.current) { - hiddenTextareaRef.current.select(); - } - }, 0); - } - } - }, []);''' - -new_handle_display_click = ''' // Removed handleDisplayClick - let the hidden textarea handle all mouse events naturally''' - -content = content.replace(old_handle_display_click, new_handle_display_click) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed text selection behavior:") -print(" - Made hidden textarea capture all mouse events (higher z-index)") -print(" - Made visual display non-interactive (pointerEvents: 'none')") -print(" - Removed interfering click handlers") -print(" - Should now behave like a normal text input for selection") -print(" - Clicking, dragging, double-click, triple-click should all work normally") diff --git a/fix_text_selection_functionality.py b/fix_text_selection_functionality.py deleted file mode 100644 index 8d2f586a11..0000000000 --- a/fix_text_selection_functionality.py +++ /dev/null @@ -1,136 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Fixing text selection functionality (highlight, double-click, triple-click)...") - -# The issue is that we have a hidden textarea and a visual display layer -# We need to make sure the visual layer doesn't interfere with text selection - -# Find the visual display div and update its properties -old_display_div = ''' {/* Visual display with action pills and cursor */} -
- {renderContent()} -
''' - -new_display_div = ''' {/* Visual display with action pills and cursor */} -
- {renderContent()} -
''' - -content = content.replace(old_display_div, new_display_div) - -# Also need to update the hidden textarea to be more accessible for selection -old_hidden_textarea = ''' className="absolute inset-0 w-full h-full opacity-0 pointer-events-auto resize-none" - style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0, - zIndex: 1, - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - }}''' - -new_hidden_textarea = ''' className="absolute inset-0 w-full h-full resize-none" - style={{ - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - opacity: 0.01, // Nearly invisible but still selectable - zIndex: 1, - background: 'transparent', - border: 'none', - outline: 'none', - resize: 'none', - color: 'transparent', // Hide text but keep selection - caretColor: 'transparent', // Hide caret (we show our own) - }}''' - -content = content.replace(old_hidden_textarea, new_hidden_textarea) - -# Update handleDisplayClick to handle selection events better -old_handle_click = ''' const handleDisplayClick = useCallback((e: React.MouseEvent) => { - // Don't focus if clicking on an action pill - if ((e.target as Element).closest('.action-pill-wrapper')) { - return; - } - hiddenTextareaRef.current?.focus(); - }, []);''' - -new_handle_click = ''' const handleDisplayClick = useCallback((e: React.MouseEvent) => { - // Don't focus if clicking on an action pill - if ((e.target as Element).closest('.action-pill-wrapper')) { - return; - } - - // Focus the hidden textarea for text selection - if (hiddenTextareaRef.current) { - hiddenTextareaRef.current.focus(); - - // For double/triple click, select text appropriately - if (e.detail === 2) { - // Double click - select word (let browser handle this) - setTimeout(() => { - if (hiddenTextareaRef.current) { - hiddenTextareaRef.current.select(); - } - }, 0); - } else if (e.detail === 3) { - // Triple click - select all - setTimeout(() => { - if (hiddenTextareaRef.current) { - hiddenTextareaRef.current.select(); - } - }, 0); - } - } - }, []);''' - -content = content.replace(old_handle_click, new_handle_click) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Fixed text selection functionality:") -print(" - Added userSelect: 'text' to visual display") -print(" - Made hidden textarea slightly visible (opacity: 0.01)") -print(" - Added double-click and triple-click handling") -print(" - Preserved pill functionality while enabling text selection") -print(" - Should now support highlighting, double-click, and triple-click") diff --git a/pr_description.md b/pr_description.md new file mode 100644 index 0000000000..e87ad390ef --- /dev/null +++ b/pr_description.md @@ -0,0 +1,80 @@ +# Rich Text Input with Action and Mention Pills + +This PR introduces a sophisticated rich text input system that replaces plain text with visual pills for actions and file mentions, creating a more intuitive and modern chat interface. + +## ๐ŸŽฏ Features + +### Visual Pills +- **Action Pills**: Blue circles with white icons for `/` commands (e.g., `[Quick Task]`) +- **Mention Pills**: Blue diamonds for `@` file references (e.g., `@filename.txt`) +- **Consistent Styling**: White pill backgrounds with blue accent icons +- **Theme Support**: Adapts to light/dark modes + +### User Experience +- **Natural Text Flow**: Pills display inline with text content +- **Text Selection**: Full support for click/drag, double-click, triple-click +- **Backspace Removal**: Delete entire pills as single units +- **Proper Cursor**: Black blinking cursor with correct positioning +- **Multi-line Support**: Cursor stays aligned on line breaks + +### Components Added +- `RichChatInput.tsx`: Main rich text input with pill rendering +- `ActionPill.tsx`: Blue circle pills for actions +- `MentionPill.tsx`: Blue diamond pills for file mentions +- `MessageContent.tsx`: Enhanced message display with pills + +## ๐Ÿ”ง Technical Implementation + +### Architecture +- **Hidden Textarea**: Handles actual input and selection +- **Visual Display**: Renders pills and cursor overlay +- **Perfect Alignment**: Synchronized font, padding, and positioning +- **Event Handling**: Proper mouse/keyboard event delegation + +### Pattern Matching +- **Actions**: `/action` โ†’ `[Action Name]` โ†’ Blue circle pill +- **Mentions**: `@filename` โ†’ Blue diamond pill +- **Mixed Content**: Supports both types inline with text + +### Accessibility +- **Keyboard Navigation**: Full keyboard support maintained +- **Screen Readers**: Proper ARIA attributes and roles +- **Selection**: Standard text selection behaviors preserved + +## ๐ŸŽจ Visual Design + +### Before +``` +Hello /quick-task and @file.txt world +``` + +### After +``` +Hello [Quick Task] and @file.txt world + โ†‘ blue circle โ†‘ blue diamond +``` + +### Message History +Pills appear in sent messages maintaining the same visual style and inline flow. + +## ๐Ÿงช Testing + +Tested extensively for: +- โœ… Action pill creation via `/` command +- โœ… File mention pills via `@` command +- โœ… Text selection and highlighting +- โœ… Cursor positioning and movement +- โœ… Backspace pill removal +- โœ… Multi-line text handling +- โœ… Light/dark theme compatibility +- โœ… Message history display + +## ๐Ÿš€ Impact + +This creates a modern chat interface similar to Slack/Discord with: +- **Improved UX**: Visual pills are easier to understand than plain text +- **Better Organization**: Clear distinction between actions and file references +- **Enhanced Workflow**: Faster recognition of commands and mentions +- **Professional Appearance**: Polished, modern interface design + +The implementation maintains full backward compatibility while significantly enhancing the user experience. diff --git a/replace_textarea.py b/replace_textarea.py deleted file mode 100644 index 5e1c456fbb..0000000000 --- a/replace_textarea.py +++ /dev/null @@ -1,60 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Find and replace the textarea element with RichTextInput -textarea_start = content.find('', textarea_start) + len('') -if textarea_end == -1: - print("Textarea end not found") - exit(1) - -# Extract the old textarea -old_textarea = content[textarea_start:textarea_end] -print(f"Found textarea from {textarea_start} to {textarea_end}") - -# Create the new RichTextInput component -new_richtextinput = ''' { - setDisplayValue(newValue); - setValue(newValue); - setActions(newActions); - debouncedSaveDraft(newValue); - setHasUserTyped(true); - checkForMention(newValue, textAreaRef.current?.selectionStart || 0, textAreaRef.current!); - }} - onKeyDown={handleKeyDown} - onPaste={handlePaste} - onFocus={() => setIsFocused(true)} - onBlur={() => setIsFocused(false)} - onCompositionStart={handleCompositionStart} - onCompositionEnd={handleCompositionEnd} - placeholder={isRecording ? '' : 'โŒ˜โ†‘/โŒ˜โ†“ to navigate messages'} - disabled={isUserInputDisabled} - style={{ - maxHeight: `${maxHeight}px`, - overflowY: 'auto', - opacity: isRecording ? 0 : 1, - }} - className="w-full outline-none border-none focus:ring-0 bg-transparent px-3 pt-3 pb-1.5 pr-20 text-sm resize-none text-textStandard placeholder:text-textPlaceholder" - actions={actions} - maxHeight={maxHeight} - />''' - -# Replace the textarea with RichTextInput -content = content[:textarea_start] + new_richtextinput + content[textarea_end:] - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("Textarea replaced with RichTextInput successfully") diff --git a/simple_inline_pills.py b/simple_inline_pills.py deleted file mode 100644 index 0cc0be2166..0000000000 --- a/simple_inline_pills.py +++ /dev/null @@ -1,50 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Simple approach: Just remove the "Selected Actions Pills" section -# Find the section that starts with {/* Selected Actions Pills */} -start_marker = '{/* Selected Actions Pills */}' -start_pos = content.find(start_marker) - -if start_pos != -1: - # Find the end of this section - look for the closing div and brace - # We need to find the matching closing brace for the conditional - lines = content[start_pos:].split('\n') - brace_count = 0 - end_line = 0 - - for i, line in enumerate(lines): - if i == 0: # First line with the comment - continue - - # Count braces to find the end of the conditional - open_braces = line.count('{') - close_braces = line.count('}') - brace_count += open_braces - close_braces - - # Look for the end pattern - if ')}\n' in line or line.strip() == ')}': - end_line = i + 1 - break - - if end_line > 0: - # Calculate the end position - end_pos = start_pos + len('\n'.join(lines[:end_line])) - - # Remove the section - content = content[:start_pos] + content[end_pos:] - - print(f"Removed Selected Actions Pills section from position {start_pos} to {end_pos}") - else: - print("Could not find end of Selected Actions Pills section") -else: - print("Selected Actions Pills section not found") - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("ChatInput.tsx updated - Selected Actions Pills section removed") diff --git a/test_action_flow.py b/test_action_flow.py deleted file mode 100644 index 1fd1a5c761..0000000000 --- a/test_action_flow.py +++ /dev/null @@ -1,67 +0,0 @@ -# Let's create a simple test to verify the action flow -print("๐Ÿงช Testing Action Flow Components") -print("=" * 50) - -# Check if files exist and have the right structure -import os - -files_to_check = [ - 'ui/desktop/src/components/ChatInput.tsx', - 'ui/desktop/src/components/RichChatInput.tsx', - 'ui/desktop/src/components/ActionPill.tsx', - 'ui/desktop/src/components/ActionPopover.tsx' -] - -for file_path in files_to_check: - if os.path.exists(file_path): - print(f"โœ… {file_path} exists") - - with open(file_path, 'r') as f: - content = f.read() - - if 'ChatInput.tsx' in file_path: - if 'handleActionSelect' in content: - print(" โœ… handleActionSelect function found") - if 'actionPopover' in content: - print(" โœ… actionPopover state found") - if 'cursorPosition' in content: - print(" โœ… cursorPosition handling found") - - elif 'RichChatInput.tsx' in file_path: - if 'actionRegex' in content: - print(" โœ… actionRegex found") - if 'ActionPill' in content: - print(" โœ… ActionPill import found") - if 'renderContent' in content: - print(" โœ… renderContent function found") - - elif 'ActionPill.tsx' in file_path: - if 'ActionPillProps' in content: - print(" โœ… ActionPillProps interface found") - - elif 'ActionPopover.tsx' in file_path: - if 'onSelect' in content: - print(" โœ… onSelect prop found") - else: - print(f"โŒ {file_path} missing") - -print("\n๐Ÿ” Key Integration Points:") -print("1. ChatInput imports RichChatInput โœ…") -print("2. RichChatInput imports ActionPill โœ…") -print("3. ChatInput has handleActionSelect โœ…") -print("4. ActionPopover calls handleActionSelect โœ…") -print("5. RichChatInput renders [Action] as pills โœ…") - -print("\n๐ŸŽฏ Test Plan:") -print("1. Type '/' in chat input") -print("2. Action popover should appear") -print("3. Click an action (e.g., 'Quick Task')") -print("4. Should see '[Quick Task]' appear as a pill in the input") -print("5. Cursor should be positioned after the pill") - -print("\n๐Ÿ“‹ Debug Steps:") -print("1. Open browser dev tools") -print("2. Look for console logs starting with ๐ŸŽฏ, ๐Ÿ“‹, ๐Ÿ“, etc.") -print("3. Check if handleActionSelect is called") -print("4. Check if text replacement happens") -print("5. Check if RichChatInput re-renders with new value") diff --git a/test_basic_functionality.py b/test_basic_functionality.py deleted file mode 100644 index 56df53c110..0000000000 --- a/test_basic_functionality.py +++ /dev/null @@ -1,80 +0,0 @@ -# Let's create a simple test to verify if the basic text replacement is working -print("๐Ÿงช Testing Basic Text Replacement") -print("=" * 50) - -# Read the handleActionSelect function -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -# Check if the function exists and has the right structure -if 'handleActionSelect' in content: - print("โœ… handleActionSelect function found") - - # Check for key components - if 'setDisplayValue(newValue)' in content: - print("โœ… setDisplayValue call found") - if 'setValue(newValue)' in content: - print("โœ… setValue call found") - if 'actionInfo.label' in content: - print("โœ… actionInfo.label usage found") - if 'lastSlashIndex' in content: - print("โœ… slash detection logic found") - - # Extract the function for analysis - start = content.find('const handleActionSelect = (actionId: string) => {') - if start != -1: - # Find the end of the function - brace_count = 0 - pos = start - while pos < len(content): - if content[pos] == '{': - brace_count += 1 - elif content[pos] == '}': - brace_count -= 1 - if brace_count == 0: - end = pos + 1 - break - pos += 1 - - function_code = content[start:end] - print(f"\n๐Ÿ“ Function length: {len(function_code)} characters") - - # Check for potential issues - if 'cursorPosition = 0' in function_code: - print("โš ๏ธ WARNING: cursorPosition hardcoded to 0") - if 'actionPopover.cursorPosition' in function_code: - print("โœ… Using actionPopover.cursorPosition") - if 'console.log' in function_code: - print("โœ… Debug logging present") - -else: - print("โŒ handleActionSelect function not found") - -print("\n๐Ÿ” Checking RichChatInput integration...") - -# Check RichChatInput -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - rich_content = f.read() - -if 'actionRegex = /\\[([^\\]]+)\\]/g' in rich_content: - print("โœ… Action regex pattern found") -if 'ActionPill' in rich_content: - print("โœ… ActionPill component imported") -if 'renderContent' in rich_content: - print("โœ… renderContent function found") - -print("\n๐ŸŽฏ Next Steps:") -print("1. Open browser dev tools") -print("2. Type '/' in chat input") -print("3. Click an action") -print("4. Look for these console messages:") -print(" - ๐ŸŽฏ ActionPopover: handleItemClick called") -print(" - ๐ŸŽฏ handleActionSelect called with:") -print(" - ๐Ÿ“ Current state:") -print(" - ๐Ÿ”„ Text replacement:") -print(" - ๐ŸŽจ RichChatInput renderContent called") - -print("\n๐Ÿ’ก If no console logs appear:") -print("- ActionPopover might not be calling onSelect") -print("- handleActionSelect might not be connected") -print("- Check for JavaScript errors in console") diff --git a/test_mention_functionality.py b/test_mention_functionality.py deleted file mode 100644 index 2005a6ca00..0000000000 --- a/test_mention_functionality.py +++ /dev/null @@ -1,63 +0,0 @@ -print("๐Ÿงช Testing Mention Pill Functionality") -print("=" * 50) - -# Check if all files exist and have the right structure -import os - -files_to_check = [ - 'ui/desktop/src/components/MentionPill.tsx', - 'ui/desktop/src/components/RichChatInput.tsx', - 'ui/desktop/src/components/MessageContent.tsx', - 'ui/desktop/src/components/ChatInput.tsx' -] - -for file_path in files_to_check: - if os.path.exists(file_path): - print(f"โœ… {file_path} exists") - - with open(file_path, 'r') as f: - content = f.read() - - if 'MentionPill.tsx' in file_path: - if 'MentionPillProps' in content: - print(" โœ… MentionPillProps interface found") - if 'fileName' in content and 'filePath' in content: - print(" โœ… fileName and filePath props found") - - elif 'RichChatInput.tsx' in file_path: - if 'import MentionPill' in content: - print(" โœ… MentionPill import found") - else: - print(" โŒ MentionPill import missing!") - if 'mentionRegex' in content: - print(" โœ… mentionRegex found") - if 'handleRemoveMention' in content: - print(" โœ… handleRemoveMention function found") - - elif 'MessageContent.tsx' in file_path: - if 'import MentionPill' in content: - print(" โœ… MentionPill import found") - else: - print(" โŒ MentionPill import missing!") - if 'mentionRegex' in content: - print(" โœ… mentionRegex found") - - elif 'ChatInput.tsx' in file_path: - if 'handleMentionFileSelect' in content: - print(" โœ… handleMentionFileSelect function found") - if '@${fileName}' in content: - print(" โœ… @filename format creation found") - else: - print(f"โŒ {file_path} missing") - -print("\n๐ŸŽฏ Test Plan:") -print("1. Type '@' in chat input") -print("2. Select a file from the popover") -print("3. Should see green pill with filename") -print("4. Check browser console for debug logs") - -print("\n๐Ÿ“‹ Debug Steps:") -print("1. Open browser dev tools") -print("2. Look for console logs starting with ๐Ÿ“, ๐Ÿ”, โœ…") -print("3. Check if MentionPill component renders") -print("4. Verify @filename pattern is detected") diff --git a/update_chatinput_mention_handling.py b/update_chatinput_mention_handling.py deleted file mode 100644 index 27d91aee97..0000000000 --- a/update_chatinput_mention_handling.py +++ /dev/null @@ -1,67 +0,0 @@ -import re - -# Read the ChatInput file -with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f: - content = f.read() - -print("Updating ChatInput to convert @filename to pills when selected...") - -# Find the handleMentionFileSelect function and update it to create pill format -old_mention_select = ''' const handleMentionFileSelect = (filePath: string) => { - const beforeMention = displayValue.slice(0, mentionPopover.mentionStart); - const afterMention = displayValue.slice( - textAreaRef.current?.selectionStart || displayValue.length - ); - const newValue = `${beforeMention}${filePath}${afterMention}`; - - setDisplayValue(newValue); - setValue(newValue); - setMentionPopover((prev) => ({ ...prev, isOpen: false })); - textAreaRef.current?.focus(); - - // Set cursor position after the inserted file path - setTimeout(() => { - if (textAreaRef.current) { - // Cursor positioning handled by RichChatInput - // Focus handled by RichChatInput - } - }, 0); - };''' - -new_mention_select = ''' const handleMentionFileSelect = (filePath: string) => { - const beforeMention = displayValue.slice(0, mentionPopover.mentionStart); - const afterMention = displayValue.slice( - textAreaRef.current?.selectionStart || displayValue.length - ); - - // Extract just the filename from the path for the pill - const fileName = filePath.split('/').pop() || filePath; - const mentionText = `@${fileName}`; - const newValue = `${beforeMention}${mentionText} ${afterMention}`; - - setDisplayValue(newValue); - setValue(newValue); - setMentionPopover((prev) => ({ ...prev, isOpen: false })); - textAreaRef.current?.focus(); - - // Set cursor position after the inserted mention and space - const newCursorPosition = beforeMention.length + mentionText.length + 1; - setTimeout(() => { - if (textAreaRef.current) { - textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition); - textAreaRef.current.focus(); - } - }, 0); - };''' - -content = content.replace(old_mention_select, new_mention_select) - -# Write the modified content back -with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Updated ChatInput mention handling:") -print(" - Modified handleMentionFileSelect to create @filename format") -print(" - Extracts filename from full path for cleaner pills") -print(" - Adds space after mention for better UX") -print(" - Sets cursor position properly after insertion") diff --git a/update_mention_pill_styling.py b/update_mention_pill_styling.py deleted file mode 100644 index 5752a555bf..0000000000 --- a/update_mention_pill_styling.py +++ /dev/null @@ -1,31 +0,0 @@ -import re - -# Read the MentionPill file -with open('ui/desktop/src/components/MentionPill.tsx', 'r') as f: - content = f.read() - -print("Updating MentionPill styling to match ActionPill (white background, same spacing)...") - -# Update the variantClasses to match ActionPill styling -old_variant_classes = ''' const variantClasses = { - default: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700", - message: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700" - };''' - -new_variant_classes = ''' const variantClasses = { - default: "bg-bgProminent text-textProminentInverse border-borderProminent", - message: "bg-bgProminent text-textProminentInverse border-borderProminent" - };''' - -content = content.replace(old_variant_classes, new_variant_classes) - -# Write the modified content back -with open('ui/desktop/src/components/MentionPill.tsx', 'w') as f: - f.write(content) - -print("โœ… Updated MentionPill styling:") -print(" - Changed from green colors to theme-aware white background") -print(" - Now uses bg-bgProminent text-textProminentInverse border-borderProminent") -print(" - Same styling as ActionPill (white background, proper contrast)") -print(" - Maintains same spacing and padding (px-2 py-1 text-xs)") -print(" - Both pills now have consistent appearance") diff --git a/update_message_content_for_mentions.py b/update_message_content_for_mentions.py deleted file mode 100644 index 578578abb9..0000000000 --- a/update_message_content_for_mentions.py +++ /dev/null @@ -1,249 +0,0 @@ -import re - -# Read the MessageContent file -with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f: - content = f.read() - -print("Updating MessageContent to support mention pills in sent messages...") - -# Add MentionPill import -old_imports = """import React, { useMemo } from 'react'; -import MarkdownContent from './MarkdownContent'; -import ActionPill from './ActionPill'; -import { Zap, Code, FileText, Search, Play, Settings } from 'lucide-react';""" - -new_imports = """import React, { useMemo } from 'react'; -import MarkdownContent from './MarkdownContent'; -import ActionPill from './ActionPill'; -import MentionPill from './MentionPill'; -import { Zap, Code, FileText, Search, Play, Settings } from 'lucide-react';""" - -content = content.replace(old_imports, new_imports) - -# Update the parsedContent logic to handle both actions and mentions -old_parsing_logic = ''' const parsedContent = useMemo(() => { - // Find all [Action] patterns and replace them with pill components - const actionRegex = /\[([^\]]+)\]/g; - const parts: Array<{ type: 'text' | 'action'; content: string; actionId?: string }> = []; - let currentIndex = 0; - let match; - - while ((match = actionRegex.exec(content)) !== null) { - // Add text before the action - if (match.index > currentIndex) { - parts.push({ - type: 'text', - content: content.slice(currentIndex, match.index), - }); - } - - // Add the action - const actionLabel = match[1]; - const actionId = getActionIdFromLabel(actionLabel); - - parts.push({ - type: 'action', - content: actionLabel, - actionId: actionId, - }); - - currentIndex = match.index + match[0].length; - } - - // Add remaining text - if (currentIndex < content.length) { - parts.push({ - type: 'text', - content: content.slice(currentIndex), - }); - } - - // If no actions found, return the original content as a single text part - if (parts.length === 0) { - parts.push({ - type: 'text', - content: content, - }); - } - - return parts; - }, [content]);''' - -new_parsing_logic = ''' const parsedContent = useMemo(() => { - // Find all [Action] and @mention patterns and replace them with pill components - const actionRegex = /\[([^\]]+)\]/g; - const mentionRegex = /@([^\s]+)/g; - const parts: Array<{ type: 'text' | 'action' | 'mention'; content: string; actionId?: string; fileName?: string }> = []; - - // Find all matches and sort by position - const allMatches = []; - - // Find all action matches - let actionMatch; - actionRegex.lastIndex = 0; - while ((actionMatch = actionRegex.exec(content)) !== null) { - allMatches.push({ - type: 'action', - index: actionMatch.index, - length: actionMatch[0].length, - content: actionMatch[1] - }); - } - - // Find all mention matches - let mentionMatch; - mentionRegex.lastIndex = 0; - while ((mentionMatch = mentionRegex.exec(content)) !== null) { - allMatches.push({ - type: 'mention', - index: mentionMatch.index, - length: mentionMatch[0].length, - content: mentionMatch[1] // filename without @ - }); - } - - // Sort matches by position - allMatches.sort((a, b) => a.index - b.index); - - let currentIndex = 0; - - // Process all matches in order - for (const match of allMatches) { - // Add text before this match - if (match.index > currentIndex) { - parts.push({ - type: 'text', - content: content.slice(currentIndex, match.index), - }); - } - - if (match.type === 'action') { - // Add the action - const actionLabel = match.content; - const actionId = getActionIdFromLabel(actionLabel); - - parts.push({ - type: 'action', - content: actionLabel, - actionId: actionId, - }); - } else if (match.type === 'mention') { - // Add the mention - parts.push({ - type: 'mention', - content: match.content, // filename without @ - fileName: match.content, - }); - } - - currentIndex = match.index + match.length; - } - - // Add remaining text - if (currentIndex < content.length) { - parts.push({ - type: 'text', - content: content.slice(currentIndex), - }); - } - - // If no matches found, return the original content as a single text part - if (parts.length === 0) { - parts.push({ - type: 'text', - content: content, - }); - } - - return parts; - }, [content]);''' - -content = content.replace(old_parsing_logic, new_parsing_logic) - -# Update the rendering logic to handle mention pills -old_rendering = ''' {parsedContent.map((part, index) => { - if (part.type === 'action' && part.actionId) { - const actionInfo = getActionInfo(part.actionId); - return ( - - ); - } else if (part.content.trim()) { - return ( - $1') - .replace(/\*(.*?)\*/g, '$1') - .replace(/`(.*?)`/g, '$1') - .replace(/\\n/g, '
') - }} - /> - ); - } - return null; - })}''' - -new_rendering = ''' {parsedContent.map((part, index) => { - if (part.type === 'action' && part.actionId) { - const actionInfo = getActionInfo(part.actionId); - return ( - - ); - } else if (part.type === 'mention' && part.fileName) { - return ( - - ); - } else if (part.content.trim()) { - return ( - $1') - .replace(/\*(.*?)\*/g, '$1') - .replace(/`(.*?)`/g, '$1') - .replace(/\\n/g, '
') - }} - /> - ); - } - return null; - })}''' - -content = content.replace(old_rendering, new_rendering) - -# Write the modified content back -with open('ui/desktop/src/components/MessageContent.tsx', 'w') as f: - f.write(content) - -print("โœ… Updated MessageContent for mention pills:") -print(" - Added MentionPill import") -print(" - Updated parsing logic to detect both [Action] and @mention patterns") -print(" - Added mention pill rendering in sent messages") -print(" - Mentions will appear as green pills in message history") diff --git a/update_pill_icons.py b/update_pill_icons.py deleted file mode 100644 index 632a899ea4..0000000000 --- a/update_pill_icons.py +++ /dev/null @@ -1,70 +0,0 @@ -import re - -print("Updating pill icons: blue diamond for documents, blue circle for actions...") - -# First, update MentionPill to use blue diamond icon -with open('ui/desktop/src/components/MentionPill.tsx', 'r') as f: - mention_content = f.read() - -# Replace the File import and icon with a blue diamond -old_mention_imports = "import { X, File } from 'lucide-react';" -new_mention_imports = "import { X, Diamond } from 'lucide-react';" - -mention_content = mention_content.replace(old_mention_imports, new_mention_imports) - -# Replace the File icon with Diamond icon and add blue color -old_mention_icon = ''' - - {fileName} - ''' - -new_mention_icon = ''' - - {fileName} - ''' - -mention_content = mention_content.replace(old_mention_icon, new_mention_icon) - -# Write the updated MentionPill -with open('ui/desktop/src/components/MentionPill.tsx', 'w') as f: - f.write(mention_content) - -print("โœ… Updated MentionPill:") -print(" - Changed from File icon to Diamond icon") -print(" - Added blue color (text-blue-500 fill-blue-500)") - -# Now update ActionPill to use blue circle icons -with open('ui/desktop/src/components/ActionPill.tsx', 'r') as f: - action_content = f.read() - -# We need to modify how the icon is rendered to add blue color -# Find the icon rendering section -old_action_icon = ''' - {icon} - {label} - ''' - -new_action_icon = ''' - -
- - {icon} - - - {label} - ''' - -action_content = action_content.replace(old_action_icon, new_action_icon) - -# Write the updated ActionPill -with open('ui/desktop/src/components/ActionPill.tsx', 'w') as f: - f.write(action_content) - -print("โœ… Updated ActionPill:") -print(" - Added blue circle background for icons") -print(" - Icons now appear as white symbols on blue circles") - -print("\n๐ŸŽฏ Result:") -print(" - Document pills: Blue diamond icon + filename") -print(" - Action pills: Blue circle with white action icon + label") -print(" - Both maintain white pill background with consistent styling") diff --git a/update_richtextinput_for_mentions.py b/update_richtextinput_for_mentions.py deleted file mode 100644 index 3bae6b0ada..0000000000 --- a/update_richtextinput_for_mentions.py +++ /dev/null @@ -1,93 +0,0 @@ -import re - -# Read the RichChatInput file -with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f: - content = f.read() - -print("Updating RichChatInput to support mention pills...") - -# Add MentionPill import -old_imports = "import { ActionPill } from './ActionPill';" -new_imports = """import { ActionPill } from './ActionPill'; -import MentionPill from './MentionPill';""" - -content = content.replace(old_imports, new_imports) - -# Update the renderContent function to handle both actions and mentions -# Find the while loop that processes actions and extend it to handle mentions too -old_regex_section = ''' const parts: React.ReactNode[] = []; - const actionRegex = /\[([^\]]+)\]/g; - let lastIndex = 0; - let match; - let keyCounter = 0; - let currentPos = 0; // Track position for cursor placement''' - -new_regex_section = ''' const parts: React.ReactNode[] = []; - const actionRegex = /\[([^\]]+)\]/g; - const mentionRegex = /@([^\s]+)/g; // Match @filename patterns - let lastIndex = 0; - let match; - let keyCounter = 0; - let currentPos = 0; // Track position for cursor placement''' - -content = content.replace(old_regex_section, new_regex_section) - -# Now we need to process both actions and mentions in the correct order -# Find the existing while loop and replace it with a more comprehensive approach -old_while_loop_start = ''' console.log('๐ŸŽจ RichChatInput renderContent called with value:', value); - console.log('๐Ÿ” Looking for action patterns with regex:', actionRegex); - - while ((match = actionRegex.exec(value)) !== null) {''' - -new_while_loop_start = ''' console.log('๐ŸŽจ RichChatInput renderContent called with value:', value); - console.log('๐Ÿ” Looking for action and mention patterns with regex:', { actionRegex, mentionRegex }); - - // Find all actions and mentions, then sort by position - const allMatches = []; - - // Find all action matches - let actionMatch; - actionRegex.lastIndex = 0; // Reset regex - while ((actionMatch = actionRegex.exec(value)) !== null) { - allMatches.push({ - type: 'action', - match: actionMatch, - index: actionMatch.index, - length: actionMatch[0].length, - content: actionMatch[1] - }); - } - - // Find all mention matches - let mentionMatch; - mentionRegex.lastIndex = 0; // Reset regex - while ((mentionMatch = mentionRegex.exec(value)) !== null) { - allMatches.push({ - type: 'mention', - match: mentionMatch, - index: mentionMatch.index, - length: mentionMatch[0].length, - content: mentionMatch[1] // filename without @ - }); - } - - // Sort matches by position - allMatches.sort((a, b) => a.index - b.index); - - console.log('๐Ÿ” Found matches:', allMatches); - - // Process all matches in order - for (const matchData of allMatches) { - const { type, match, index, length, content } = matchData;''' - -content = content.replace(old_while_loop_start, new_while_loop_start) - -# Write the modified content back -with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f: - f.write(content) - -print("โœ… Updated RichChatInput imports and regex setup:") -print(" - Added MentionPill import") -print(" - Added mentionRegex to detect @filename patterns") -print(" - Started updating processing logic to handle both actions and mentions") -print(" - Next step: Update the processing loop to render mention pills")