From 4f1715913e679c2c5c140f9840d6f92e74c904a8 Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Sat, 19 Apr 2025 11:58:48 -0400 Subject: [PATCH] Co-authored-by: Majicmaj --- src/views/TestView/MentionTextfield.css | 152 ++++++++++++++++ src/views/TestView/MentionTextfield.jsx | 227 ++++++++++++++++++++++++ src/views/TestView/Test.jsx | 13 +- 3 files changed, 387 insertions(+), 5 deletions(-) create mode 100644 src/views/TestView/MentionTextfield.css create mode 100644 src/views/TestView/MentionTextfield.jsx diff --git a/src/views/TestView/MentionTextfield.css b/src/views/TestView/MentionTextfield.css new file mode 100644 index 0000000..40c40ad --- /dev/null +++ b/src/views/TestView/MentionTextfield.css @@ -0,0 +1,152 @@ +.task-editor-container { + background-color: #2d2d2d; + color: #ffffff; + padding: 15px; + border-radius: 8px; + max-width: 500px; + margin: 20px auto; +} + +.smart-task-input { + width: 100%; + padding: 10px; + margin-bottom: 10px; + border: none; + background-color: transparent; + color: #ffffff; + font-size: 1.2em; + outline: none; +} + +.task-description-input { + width: 100%; + padding: 10px; + margin-bottom: 10px; + border: none; + background-color: transparent; + color: #ffffff; + font-size: 1em; + min-height: 80px; + resize: vertical; + outline: none; +} + +.task-attributes { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 15px; +} + +.attribute-tag { + background-color: #444; + padding: 5px 10px; + border-radius: 15px; + font-size: 0.9em; + display: flex; + align-items: center; + cursor: pointer; +} + +.remove-tag { + margin-left: 5px; + cursor: pointer; + font-weight: bold; +} + +.task-actions { + display: flex; + justify-content: space-between; + align-items: center; +} + +.project-select select { + padding: 5px; + border-radius: 4px; + background-color: #444; + color: #ffffff; + border: none; + cursor: pointer; +} + +.action-buttons button { + padding: 8px 15px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 1em; + margin-left: 10px; +} + +.cancel-button { + background-color: #666; + color: #ffffff; +} + +.add-task-button { + background-color: #d9534f; + color: #ffffff; +} + +.smart-task-input { + width: 100%; + position: absolute; + z-index: 1; + /* color: transparent; + caret-color: white; + + + padding: 0px; + margin: 0; + border: none; + outline: none; + box-sizing: border-box; + + +} + +.smart-task-display { + position: absolute; + width: 100%; + /* top: 0; + left: 0; */ + + z-index: 10; + pointer-events: none; + + padding: 0px; + margin: 0; + border: none; + + overflow-y: auto; + word-wrap: break-word; + white-space: pre-wrap; + box-sizing: border-box; +} +.smart-task-common { + font-size: 1.2em; + line-height: 1.2em; + font-family: inherit; +} + +.highlight-date { + color: #f08080; + background-color: #ffffff; +} + +.highlight-label { + color: #add8e6; +} + +.highlight-priority { + color: #ffb6c1; +} + +.task-input { + position: relative; + width: 100%; + background-color: #2d2d2d; + color: #ffffff; + border-radius: 8px; + box-sizing: border-box; +} diff --git a/src/views/TestView/MentionTextfield.jsx b/src/views/TestView/MentionTextfield.jsx new file mode 100644 index 0000000..66c95ba --- /dev/null +++ b/src/views/TestView/MentionTextfield.jsx @@ -0,0 +1,227 @@ +import { useEffect, useRef, useState } from 'react' +import './MentionTextfield.css' // We'll assume a CSS file for basic styling + +// Helper function to render text with highlighting + +const MentionTextfield = ({ initialTask = {}, onCancel, onAddTask }) => { + // State to hold the task details + const [taskTitle, setTaskTitle] = useState(initialTask.title || '') + const [taskDescription, setTaskDescription] = useState( + initialTask.description || '', + ) + const [selectedDate, setSelectedDate] = useState(initialTask.date || null) + const [selectedPriority, setSelectedPriority] = useState( + initialTask.priority || null, + ) + const [selectedLabels, setSelectedLabels] = useState(initialTask.labels || []) + const [reminders, setReminders] = useState(initialTask.reminders || []) + const [selectedProject, setSelectedProject] = useState( + initialTask.project || 'Inbox', + ) + + const [cursorPosition, setCursorPosition] = useState(0) // State to track cursor position + const [showCursor, setShowCursor] = useState(false) // State to toggle cursor visibility + + // Ref for the input field (if needed for more advanced handling) + const titleInputRef = useRef(null) + + // Effect to update bottom tags based on title parsing + useEffect(() => { + // Basic parsing logic + const lowerCaseTitle = taskTitle.toLowerCase() + const extractedDate = lowerCaseTitle.includes('tomorrow') + ? 'Tomorrow' + : null + + const labelMatches = taskTitle.match(/@(\w+)/g) + const extractedLabels = labelMatches + ? labelMatches.map(match => match.substring(1)) + : [] + + const priorityMatch = taskTitle.match(/P(\d)/) + const extractedPriority = priorityMatch ? `P${priorityMatch[1]}` : null + + setSelectedDate(extractedDate) + setSelectedLabels(extractedLabels) + setSelectedPriority(extractedPriority) + }, [taskTitle]) // Re-run effect when taskTitle changes + + // Handlers for removing attributes (same as before) + const removeDate = () => setSelectedDate(null) // Note: This won't remove from the input field text + const removePriority = () => setSelectedPriority(null) // Note: This won't remove from the input field text + const removeLabel = labelToRemove => { + // Note: This won't remove from the input field text + setSelectedLabels(selectedLabels.filter(label => label !== labelToRemove)) + } + const removeReminder = reminderToRemove => { + setReminders(reminders.filter(reminder => reminder !== reminderToRemove)) + } + + const handleAddTask = () => { + const newTask = { + title: taskTitle, + description: taskDescription, + date: selectedDate, // These come from the parsing effect + priority: selectedPriority, // These come from the parsing effect + labels: selectedLabels, // These come from the parsing effect + reminders: reminders, + project: selectedProject, + } + onAddTask(newTask) // Call the provided add task function + } + const renderHighlightedText = (text, position) => { + const parts = [] + let lastIndex = 0 + + // Regex to find patterns: Tomorrow, @label, P followed by a digit + const regex = /(Tomorrow)|(@\w+)|(P\d)/gi + let match + + while ((match = regex.exec(text)) !== null) { + const matchedText = match[0] + const matchIndex = match.index + + // Add text before the match + if (matchIndex > lastIndex) { + parts.push(text.substring(lastIndex, matchIndex)) + } + + // Add the highlighted part + let className = '' + if (matchedText.toLowerCase() === 'tomorrow') { + className = 'highlight-date' + } else if (matchedText.startsWith('@')) { + className = 'highlight-label' + } else if (matchedText.startsWith('P')) { + className = 'highlight-priority' + } + + parts.push( + + {matchedText} + , + ) + + lastIndex = regex.lastIndex + } + + // Add any remaining text after the last match + if (lastIndex < text.length) { + parts.push(text.substring(lastIndex)) + } + + return
{parts}
+ } + + return ( +
+
+