From 73b6343a4381a21c42ac55f04ce6e2d41b27c433 Mon Sep 17 00:00:00 2001 From: corsacca Date: Thu, 7 May 2026 13:55:55 +0100 Subject: [PATCH] CMS: Put Documents component in a tiptap node --- app/components/admin/RichTextEditor.vue | 97 +++++++++++++++++++++++-- app/utils/tiptapGeneralResources.ts | 2 +- 2 files changed, 91 insertions(+), 8 deletions(-) diff --git a/app/components/admin/RichTextEditor.vue b/app/components/admin/RichTextEditor.vue index 6ac1035e..497717b4 100644 --- a/app/components/admin/RichTextEditor.vue +++ b/app/components/admin/RichTextEditor.vue @@ -215,6 +215,48 @@ function insertVerse() { }).run() } +function insertGeneralResources() { + editor.value?.chain().focus().insertContent({ + type: 'generalResources', + attrs: { useDocuments: false, layout: 'on-sidebar-page' } + }).run() +} + +function toggleGeneralResourcesUseDocuments() { + const e = editor.value + if (!e) return + const current = e.getAttributes('generalResources') + e.chain().focus().updateAttributes('generalResources', { + useDocuments: !current.useDocuments + }).run() +} + +function setGeneralResourcesLayout(layout: 'on-sidebar-page' | 'on-page') { + editor.value?.chain().focus().updateAttributes('generalResources', { layout }).run() +} + +function generalResourcesAttr(key: K): unknown { + return editor.value?.getAttributes('generalResources')?.[key] +} + +const customNodeMenuItems = computed(() => [ + { + label: 'UUPG list', + icon: 'i-lucide-globe', + onSelect: () => insertUupgsList() + }, + { + label: 'Verse', + icon: 'i-lucide-book-open', + onSelect: () => insertVerse() + }, + { + label: 'Adoption resources', + icon: 'i-lucide-library', + onSelect: () => insertGeneralResources() + } +]) + // Clicks on the padding area around the ProseMirror content don't move // the cursor by default. Forward those clicks to the editor and focus // at end-of-doc so the click anywhere inside the body area starts editing. @@ -278,8 +320,44 @@ function onBodyClick(e: MouseEvent) { - - + + + +
@@ -315,7 +393,8 @@ function onBodyClick(e: MouseEvent) { .tiptap-body :deep(iframe) { max-width: 100%; } .tiptap-body :deep(.ProseMirror:focus) { outline: none; } -.tiptap-body :deep(.doxa-uupgs-list-editor-chip) { +.tiptap-body :deep(.doxa-uupgs-list-editor-chip), +.tiptap-body :deep(.doxa-general-resources-editor-chip) { display: block; margin: 0.75rem 0; padding: 0.75rem 1rem; @@ -326,19 +405,23 @@ function onBodyClick(e: MouseEvent) { user-select: none; cursor: grab; } -.tiptap-body :deep(.doxa-uupgs-list-editor-chip.is-selected) { +.tiptap-body :deep(.doxa-uupgs-list-editor-chip.is-selected), +.tiptap-body :deep(.doxa-general-resources-editor-chip.is-selected) { outline: 2px solid var(--ui-primary); outline-offset: 1px; } -.tiptap-body :deep(.doxa-uupgs-list-editor-chip__header) { +.tiptap-body :deep(.doxa-uupgs-list-editor-chip__header), +.tiptap-body :deep(.doxa-general-resources-editor-chip__header) { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; font-size: 0.875rem; } -.tiptap-body :deep(.doxa-uupgs-list-editor-chip__icon) { font-size: 1rem; } -.tiptap-body :deep(.doxa-uupgs-list-editor-chip__detail) { +.tiptap-body :deep(.doxa-uupgs-list-editor-chip__icon), +.tiptap-body :deep(.doxa-general-resources-editor-chip__icon) { font-size: 1rem; } +.tiptap-body :deep(.doxa-uupgs-list-editor-chip__detail), +.tiptap-body :deep(.doxa-general-resources-editor-chip__detail) { margin-top: 0.25rem; font-size: 0.75rem; color: var(--ui-text-muted); diff --git a/app/utils/tiptapGeneralResources.ts b/app/utils/tiptapGeneralResources.ts index b31dae49..d72544b3 100644 --- a/app/utils/tiptapGeneralResources.ts +++ b/app/utils/tiptapGeneralResources.ts @@ -63,7 +63,7 @@ export const GeneralResourcesNode = Node.create({ const paintFrom = (n: typeof node) => { const attrs: Record = n.attrs const parts: string[] = [] - parts.push(attrs.useDocuments ? 'documents list' : 'general resources list') + parts.push(attrs.useDocuments ? 'documents list' : 'adoption resources list') if (attrs.layout && attrs.layout !== 'on-sidebar-page') parts.push(`layout: ${attrs.layout}`) const detail = parts.join(' ยท ')