From 098133be20d5f6c76b47d60795ec1e044e560692 Mon Sep 17 00:00:00 2001 From: habibayman Date: Sun, 3 Aug 2025 09:08:59 +0300 Subject: [PATCH 01/13] feat(texteditor): configured to switch view/edit modes --- .../AnswersEditor/AnswersEditor.vue | 7 ++- .../TipTapEditor/TipTapEditor.vue | 63 +++++++++++++------ .../components/EditorContentWrapper.vue | 2 - .../components/image/ImageNodeView.vue | 6 +- .../components/math/FormulasMenu.vue | 2 +- .../components/math/MathNodeView.vue | 3 +- .../TipTapEditor/composables/useEditor.js | 3 +- .../composables/useMathHandling.js | 7 ++- 8 files changed, 63 insertions(+), 30 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/AnswersEditor/AnswersEditor.vue b/contentcuration/contentcuration/frontend/channelEdit/components/AnswersEditor/AnswersEditor.vue index d0f777930d..301b462fa2 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/AnswersEditor/AnswersEditor.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/AnswersEditor/AnswersEditor.vue @@ -88,7 +88,12 @@ v-else :markdown="answer.answer" /> --> - + diff --git a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue index b557eb2b9a..15ff83c561 100644 --- a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue +++ b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue @@ -1,17 +1,22 @@ @@ -103,7 +112,10 @@ {{ hintIdx + 1 }} - + @@ -124,13 +136,13 @@ import translator from '../../translator'; import { AssessmentItemTypes } from 'shared/constants'; import Checkbox from 'shared/views/form/Checkbox'; - import MarkdownViewer from 'shared/views/MarkdownEditor/MarkdownViewer/MarkdownViewer.vue'; + import TipTapEditor from 'shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue'; export default { name: 'AssessmentItemPreview', components: { - MarkdownViewer, Checkbox, + TipTapEditor, }, props: { /** diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/HintsEditor/HintsEditor.vue b/contentcuration/contentcuration/frontend/channelEdit/components/HintsEditor/HintsEditor.vue index ee9b42720a..7d87e06df8 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/HintsEditor/HintsEditor.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/HintsEditor/HintsEditor.vue @@ -31,21 +31,13 @@ {{ hintIdx + 1 }} - + - - - + @@ -90,8 +82,7 @@ import { AssessmentItemToolbarActions } from '../../constants'; import { swapElements } from 'shared/utils/helpers'; - import MarkdownEditor from 'shared/views/MarkdownEditor/MarkdownEditor/MarkdownEditor'; - import MarkdownViewer from 'shared/views/MarkdownEditor/MarkdownViewer/MarkdownViewer'; + import TipTapEditor from 'shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue'; const updateHintsOrder = hints => { return hints.map((hint, idx) => { @@ -106,8 +97,7 @@ name: 'HintsEditor', components: { AssessmentItemToolbar, - MarkdownEditor, - MarkdownViewer, + TipTapEditor, }, model: { prop: 'hints', @@ -122,20 +112,6 @@ type: Number, default: 0, }, - // Inject function to handle file uploads - handleFileUpload: { - type: Function, - default: () => {}, - }, - // Inject function to get file upload object - getFileUpload: { - type: Function, - default: () => {}, - }, - imagePreset: { - type: String, - default: null, - }, }, data() { return { diff --git a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue index 942c2428a9..d78e6a39b9 100644 --- a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue +++ b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue @@ -358,6 +358,18 @@ } }; + const handleResize = entries => { + setTimeout(() => { + for (const entry of entries) { + toolbarWidth.value = entry.contentRect.width; + } + }, 0); + }; + + const handleWindowResize = () => { + setTimeout(updateToolbarWidth, 0); + }; + const onToolClick = (tool, event) => { isMoreDropdownOpen.value = false; let target = event.currentTarget; @@ -425,15 +437,11 @@ // Set up resize observer if (toolbarRef.value && window.ResizeObserver) { - resizeObserver = new ResizeObserver(entries => { - for (const entry of entries) { - toolbarWidth.value = entry.contentRect.width; - } - }); + resizeObserver = new ResizeObserver(handleResize); resizeObserver.observe(toolbarRef.value); } else { // Fallback to window resize listener - window.addEventListener('resize', updateToolbarWidth); + window.addEventListener('resize', handleWindowResize); } document.addEventListener('click', handleClickOutside); @@ -443,7 +451,7 @@ if (resizeObserver) { resizeObserver.disconnect(); } else { - window.removeEventListener('resize', updateToolbarWidth); + window.removeEventListener('resize', handleWindowResize); } document.removeEventListener('click', handleClickOutside); }); From 71018f622fad4c876bc2dd3782639c42322cd3a5 Mon Sep 17 00:00:00 2001 From: habibayman Date: Mon, 4 Aug 2025 15:41:07 +0300 Subject: [PATCH 04/13] feat(texteditor): add minimize buttons to toolbars --- .../TipTapEditor/TipTapEditor.vue | 13 ++++- .../TipTapEditor/components/EditorToolbar.vue | 33 +++++++----- .../components/toolbar/FormatDropdown.vue | 2 +- .../components/toolbar/MobileTopBar.vue | 51 +++++++++++++------ .../components/toolbar/PasteDropdown.vue | 13 +++-- .../components/toolbar/ToolbarButton.vue | 4 +- .../composables/useToolbarActions.js | 12 +++++ .../views/TipTapEditor/assets/icon-unfold.svg | 3 ++ 8 files changed, 90 insertions(+), 41 deletions(-) create mode 100644 contentcuration/contentcuration/frontend/shared/views/TipTapEditor/assets/icon-unfold.svg diff --git a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue index 6a6bd1ef6d..e30fe90421 100644 --- a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue +++ b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue @@ -9,10 +9,14 @@
- + props.mode), + emitMinimize: () => { + // force lose focus + if (editor.value) { + emit('minimize'); + editor.value.commands.blur(); + } + }, }; }, props: { diff --git a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue index d78e6a39b9..6cb3df0ea9 100644 --- a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue +++ b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/EditorToolbar.vue @@ -114,7 +114,7 @@ />
- +
+ @@ -303,10 +308,10 @@ // TODO: Maybe these shouldnt be hardcoded? const OVERFLOW_BREAKPOINTS = { insert: 750, - script: 650, - lists: 550, - clearFormat: 450, - clipboard: 405, + script: 660, + lists: 600, + clearFormat: 500, + clipboard: 465, }; // Categories that can overflow (in order of overflow priority) @@ -321,7 +326,8 @@ listActions, scriptActions, insertTools, - } = useToolbarActions(); + minimizeAction, + } = useToolbarActions(emit); const { pasteOptions } = useDropdowns(); @@ -472,6 +478,7 @@ listActions, scriptActions, insertTools, + minimizeAction, pasteOptions, copy$, textFormattingToolbar$, @@ -495,14 +502,18 @@ .toolbar { position: relative; display: flex; - gap: 4px; + gap: 6px; align-items: center; - padding: 8px 4px; + padding: 8px; background: #f8f9fa; border-bottom: 1px solid #e1e5e9; border-radius: 8px 8px 0 0; } + .toolbar > :last-child { + margin-left: auto; + } + [role='group'] { display: flex; gap: 2px; @@ -581,10 +592,4 @@ } } - @media (max-width: 820px) { - .toolbar { - gap: 1px; - } - } - diff --git a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/FormatDropdown.vue b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/FormatDropdown.vue index a3906153cd..394cdef56b 100644 --- a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/FormatDropdown.vue +++ b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/FormatDropdown.vue @@ -211,7 +211,7 @@ gap: 8px; align-items: center; justify-content: space-between; - min-width: 80px; + min-width: 100px; padding: 6px 8px; font-size: 14px; color: #495057; diff --git a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/MobileTopBar.vue b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/MobileTopBar.vue index 4fb862d5e3..bf3a1603d7 100644 --- a/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/MobileTopBar.vue +++ b/contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/MobileTopBar.vue @@ -1,7 +1,7 @@