Completes the CMS port to feature parity with public/js/learningHub.js
(@be14578). Previously the React CMS had only a plain-textarea body,
no slide editor for presentations, and no AI content generation —
three large gaps from the vanilla app.
New components:
client/src/components/RichTextEditor.tsx — Tiptap/ProseMirror editor
with the vanilla tp-toolbar feature set: bold/italic/underline/
strike, H2/H3, bullet/ordered/quote/codeblock lists, link-with-
URL-bar, and clear formatting. Three variants (default/mini/
option) match vanilla's buildTpToolbar(mini, isOption).
client/src/pages/cms/SlideEditor.tsx — per-slide Tiptap editor +
slide navigator (move/add/remove). Slides join back to the body
column with the vanilla \n---\n separator so the Learning Hub
viewer renders them unchanged.
client/src/pages/cms/AiGenerator.tsx — generate content via three
sources (topic / upload / Nextcloud WebDAV). POSTs multipart
to /api/admin/learning/ai-generate, matching the vanilla
runAiGenerate flow exactly. WebDAV file browser uses the
existing /api/admin/learning/webdav-browse endpoint. Auto-
hides the Nextcloud tab when the user isn't connected.
Updated:
QuestionsEditor — question text, option text, per-option
explanation, and question explanation are now all Tiptap-backed
so quiz authoring matches content authoring in feel.
ContentEditor — "Generate with AI" button opens the AI panel;
presentation body uses SlideEditor; everything else uses
RichTextEditor with a 320px min height.
Dependencies added:
@tiptap/react @tiptap/pm @tiptap/starter-kit
@tiptap/extension-link @tiptap/extension-underline
Closes the largest remaining gap from the vanilla→React migration.
Vanilla had ~308 lines of HTML in cms.html plus ~1000 lines of CMS
logic in learningHub.js, all gone since the vanilla deletion at
be14578. Server endpoints under /api/learning-admin survived but
had no React UI.
New page at /cms (sidebar nav adminOnly):
client/src/pages/Cms.tsx — shell, list/edit views
client/src/pages/cms/StatsBar.tsx — 6-cell metrics
client/src/pages/cms/CategoriesPanel.tsx — list + add + delete +
status & category filters
client/src/pages/cms/ContentList.tsx — table with toolbar
(new article/quiz/pearl/
presentation), search,
publish toggle, delete
client/src/pages/cms/ContentEditor.tsx — title/category/type/
subject/body/published,
embeds QuestionsEditor
when type=quiz
client/src/pages/cms/QuestionsEditor.tsx — Q+options builder
(mcq/multi/true_false)
with per-option
explanation
client/src/pages/cms/cms-types.ts — shared CMS types
Destructive actions (delete category, delete content, delete
question) all use ConfirmModal — Daniel's no-native-dialog rule.
Intentionally NOT in this first cut (each is a follow-up if used):
• AI generation panel (vanilla lh-ai-panel)
• WebDAV file picker for AI sources
• Drag-and-drop file upload for AI ingest
• Rich-text body editor — body is a textarea
• Slide editor for presentations — body holds JSON