From 025e12976d5c0661d742cf951e3296e727fed83a Mon Sep 17 00:00:00 2001
From: Sam Chau
Date: Sat, 18 Jan 2025 13:59:56 +1030
Subject: [PATCH] feat: integrate MarkdownEditor component and update
ProfileGeneralTab for enhanced description input
---
.../components/profile/ProfileGeneralTab.jsx | 18 +-
frontend/src/components/ui/MarkdownEditor.jsx | 157 ++++++++++++++++++
frontend/src/components/ui/TextArea.jsx | 29 ++--
3 files changed, 179 insertions(+), 25 deletions(-)
create mode 100644 frontend/src/components/ui/MarkdownEditor.jsx
diff --git a/frontend/src/components/profile/ProfileGeneralTab.jsx b/frontend/src/components/profile/ProfileGeneralTab.jsx
index 17f84fc..c0b60dc 100644
--- a/frontend/src/components/profile/ProfileGeneralTab.jsx
+++ b/frontend/src/components/profile/ProfileGeneralTab.jsx
@@ -1,6 +1,6 @@
import React, {useState} from 'react';
import PropTypes from 'prop-types';
-import Textarea from '../ui/TextArea';
+import MarkdownEditor from '@ui/MarkdownEditor';
const ProfileGeneralTab = ({
name,
@@ -39,7 +39,7 @@ const ProfileGeneralTab = ({
)}
-
+
@@ -94,20 +94,14 @@ const ProfileGeneralTab = ({
Add any notes or details about this profile's
- purpose and configuration
+ purpose and configuration. Use markdown to format
+ your description.
-
@@ -142,7 +136,7 @@ const ProfileGeneralTab = ({
{tags.length > 0 ? (
-
+
{tags.map(tag => (
{
+ const [isPreview, setIsPreview] = useState(false);
+
+ const insertMarkdown = (prefix, suffix = '') => {
+ const textarea = document.querySelector('#markdown-textarea');
+ const start = textarea.selectionStart;
+ const end = textarea.selectionEnd;
+ const selectedText = value.substring(start, end);
+
+ const beforeText = value.substring(0, start);
+ const afterText = value.substring(end);
+
+ const newText = selectedText
+ ? `${beforeText}${prefix}${selectedText}${suffix}${afterText}`
+ : `${beforeText}${prefix}placeholder${suffix}${afterText}`;
+
+ onChange({target: {value: newText}});
+
+ setTimeout(() => {
+ textarea.focus();
+ const newPosition = selectedText
+ ? start + prefix.length + selectedText.length + suffix.length
+ : start + prefix.length + 'placeholder'.length;
+ textarea.setSelectionRange(newPosition, newPosition);
+ }, 0);
+ };
+
+ const controls = [
+ {
+ icon: Bold,
+ label: 'Bold',
+ action: () => insertMarkdown('**', '**')
+ },
+ {
+ icon: Italic,
+ label: 'Italic',
+ action: () => insertMarkdown('*', '*')
+ },
+ {
+ icon: Code,
+ label: 'Code',
+ action: () => insertMarkdown('`', '`')
+ },
+ {
+ icon: Link,
+ label: 'Link',
+ action: () => insertMarkdown('[', '](url)')
+ },
+ {
+ icon: ListOrdered,
+ label: 'Numbered List',
+ action: () => insertMarkdown('\n1. ')
+ },
+ {
+ icon: List,
+ label: 'Bullet List',
+ action: () => insertMarkdown('\n- ')
+ },
+ {
+ icon: Quote,
+ label: 'Quote',
+ action: () => insertMarkdown('\n> ')
+ }
+ ];
+
+ return (
+
+ {/* Markdown Controls */}
+
+ {isPreview ? (
+
+
+
+ Preview Mode
+
+
+ ) : (
+ controls.map(control => (
+
+ ))
+ )}
+
+ {/* Preview Toggle */}
+
+
+
+
+
+ {/* Editor/Preview Area */}
+
+ {isPreview ? (
+
+ {value ? (
+
{value}
+ ) : (
+
+ Nothing to preview
+
+ )}
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+MarkdownEditor.propTypes = {
+ value: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+ placeholder: PropTypes.string
+};
+
+export default MarkdownEditor;
diff --git a/frontend/src/components/ui/TextArea.jsx b/frontend/src/components/ui/TextArea.jsx
index a429a42..09e0826 100644
--- a/frontend/src/components/ui/TextArea.jsx
+++ b/frontend/src/components/ui/TextArea.jsx
@@ -1,15 +1,18 @@
-import React from "react";
-
-const Textarea = React.forwardRef(({ className, ...props }, ref) => {
- return (
-
- );
+import React from 'react';
+const Textarea = React.forwardRef(({className, ...props}, ref) => {
+ return (
+
+ );
});
+Textarea.displayName = 'Textarea';
-Textarea.displayName = "Textarea";
-
-export default Textarea;
\ No newline at end of file
+export default Textarea;