synchronisation du contenu avec la DB et amélioration du CMS
- Migration du blog et des interviews des données mockées vers PostgreSQL (Prisma). - Refonte des pages publiques en Server Components pour de meilleures performances/SEO. - Intégration d'un éditeur de texte riche (React Quill) avec titres H1-H6 et séparateurs. - Correction des erreurs de validation Prisma liées aux paramètres asynchrones (Next.js 15+). - Correction des problèmes d'affichage des modales de suspension via React Portals. - Installation de @tailwindcss/typography et correction du débordement de texte (break-words). - Implémentation des actions de modération (suspension/révocation) pour les utilisateurs et boutiques.
This commit is contained in:
78
admin/src/components/RichTextEditor.tsx
Normal file
78
admin/src/components/RichTextEditor.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
"use client";
|
||||
|
||||
import React, { useMemo, useRef } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import 'react-quill-new/dist/quill.snow.css';
|
||||
|
||||
// We need to import Quill for registration
|
||||
const ReactQuill = dynamic(async () => {
|
||||
const { default: RQ, Quill } = await import("react-quill-new");
|
||||
|
||||
// Register custom Divider Blot
|
||||
if (Quill) {
|
||||
const BlockEmbed = Quill.import('blots/block/embed') as any;
|
||||
class DividerBlot extends BlockEmbed {
|
||||
static blotName = 'divider';
|
||||
static tagName = 'hr';
|
||||
}
|
||||
Quill.register(DividerBlot);
|
||||
}
|
||||
|
||||
return RQ;
|
||||
}, {
|
||||
ssr: false,
|
||||
loading: () => <div className="h-64 w-full bg-slate-900 animate-pulse rounded-lg border border-slate-700" />
|
||||
});
|
||||
|
||||
interface RichTextEditorProps {
|
||||
value: string;
|
||||
onChange: (content: string) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export default function RichTextEditor({ value, onChange, placeholder }: RichTextEditorProps) {
|
||||
const quillRef = useRef<any>(null);
|
||||
|
||||
const modules = useMemo(() => ({
|
||||
toolbar: {
|
||||
container: [
|
||||
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
||||
['divider', 'link', 'clean'],
|
||||
],
|
||||
handlers: {
|
||||
divider: function() {
|
||||
const quill = (quillRef.current as any)?.getEditor();
|
||||
if (quill) {
|
||||
const range = quill.getSelection(true);
|
||||
quill.insertEmbed(range.index, 'divider', true);
|
||||
quill.setSelection(range.index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}), []);
|
||||
|
||||
const formats = [
|
||||
'header',
|
||||
'bold', 'italic', 'underline', 'strike',
|
||||
'list', 'bullet',
|
||||
'divider', 'link',
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="quill-dark-wrapper">
|
||||
<ReactQuill
|
||||
ref={quillRef}
|
||||
theme="snow"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
modules={modules}
|
||||
formats={formats}
|
||||
placeholder={placeholder}
|
||||
className="bg-slate-900 text-white rounded-lg overflow-hidden border border-slate-700 min-h-[300px]"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user