@qwanyx/ai-editor 1.3.13 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/components/PageEditor.d.ts +10 -0
  2. package/dist/components/PageEditor.d.ts.map +1 -0
  3. package/dist/components/PageEditor.js +294 -0
  4. package/dist/components/PageViewer.d.ts +8 -0
  5. package/dist/components/PageViewer.d.ts.map +1 -0
  6. package/dist/components/PageViewer.js +38 -0
  7. package/dist/components/RichTextEditor.d.ts +5 -1
  8. package/dist/components/RichTextEditor.d.ts.map +1 -1
  9. package/dist/components/RichTextEditor.js +11 -2
  10. package/dist/components/RichTextViewer.d.ts +3 -1
  11. package/dist/components/RichTextViewer.d.ts.map +1 -1
  12. package/dist/components/RichTextViewer.js +7 -2
  13. package/dist/components/Section.d.ts +10 -0
  14. package/dist/components/Section.d.ts.map +1 -0
  15. package/dist/components/Section.js +117 -0
  16. package/dist/components/SmartEditor.d.ts +58 -0
  17. package/dist/components/SmartEditor.d.ts.map +1 -0
  18. package/dist/components/SmartEditor.js +123 -0
  19. package/dist/context/PageContext.d.ts +35 -0
  20. package/dist/context/PageContext.d.ts.map +1 -0
  21. package/dist/context/PageContext.js +277 -0
  22. package/dist/index.d.ts +17 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +54 -1
  25. package/dist/layouts/OgilvyLayout.d.ts +5 -0
  26. package/dist/layouts/OgilvyLayout.d.ts.map +1 -0
  27. package/dist/layouts/OgilvyLayout.js +301 -0
  28. package/dist/layouts/RichTextLayout.d.ts +7 -0
  29. package/dist/layouts/RichTextLayout.d.ts.map +1 -0
  30. package/dist/layouts/RichTextLayout.js +47 -0
  31. package/dist/layouts/index.d.ts +30 -0
  32. package/dist/layouts/index.d.ts.map +1 -0
  33. package/dist/layouts/index.js +71 -0
  34. package/dist/types/index.d.ts +5 -0
  35. package/dist/types/index.d.ts.map +1 -0
  36. package/dist/types/index.js +20 -0
  37. package/dist/types/page.d.ts +151 -0
  38. package/dist/types/page.d.ts.map +1 -0
  39. package/dist/types/page.js +54 -0
  40. package/dist/utils/format.d.ts +71 -0
  41. package/dist/utils/format.d.ts.map +1 -0
  42. package/dist/utils/format.js +190 -0
  43. package/dist/utils/index.d.ts +5 -0
  44. package/dist/utils/index.d.ts.map +1 -0
  45. package/dist/utils/index.js +20 -0
  46. package/package.json +1 -1
@@ -0,0 +1,10 @@
1
+ import { PageDocument } from '../types/page';
2
+ export interface PageEditorProps {
3
+ initialDocument?: PageDocument;
4
+ onChange?: (document: PageDocument) => void;
5
+ className?: string;
6
+ isEditing?: boolean;
7
+ }
8
+ export declare function PageEditor({ initialDocument, onChange, className, isEditing, }: PageEditorProps): import("react/jsx-runtime").JSX.Element;
9
+ export default PageEditor;
10
+ //# sourceMappingURL=PageEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageEditor.d.ts","sourceRoot":"","sources":["../../src/components/PageEditor.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EAOb,MAAM,eAAe,CAAA;AAmnBtB,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,YAAY,CAAA;IAC9B,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAA;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,UAAU,CAAC,EACzB,eAAe,EACf,QAAQ,EACR,SAAS,EACT,SAAgB,GACjB,EAAE,eAAe,2CAYjB;AAED,eAAe,UAAU,CAAA"}
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PageEditor = PageEditor;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const page_1 = require("../types/page");
8
+ const PageContext_1 = require("../context/PageContext");
9
+ const Section_1 = require("./Section");
10
+ const layouts_1 = require("../layouts");
11
+ // Initialize layouts on module load
12
+ (0, layouts_1.initializeLayouts)();
13
+ // ============================================
14
+ // Styles
15
+ // ============================================
16
+ const styles = {
17
+ container: {
18
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
19
+ display: 'flex',
20
+ flexDirection: 'column',
21
+ height: '100%',
22
+ },
23
+ tabBar: {
24
+ display: 'flex',
25
+ borderBottom: '1px solid #e9ecef',
26
+ backgroundColor: '#f8f9fa',
27
+ },
28
+ tab: {
29
+ padding: '0.75rem 1.5rem',
30
+ border: 'none',
31
+ backgroundColor: 'transparent',
32
+ cursor: 'pointer',
33
+ fontSize: '0.875rem',
34
+ fontWeight: 500,
35
+ color: '#666',
36
+ borderBottom: '2px solid transparent',
37
+ transition: 'color 0.2s, border-color 0.2s',
38
+ },
39
+ tabActive: {
40
+ color: '#007bff',
41
+ borderBottomColor: '#007bff',
42
+ },
43
+ tabHover: {
44
+ color: '#333',
45
+ },
46
+ toolbar: {
47
+ display: 'flex',
48
+ gap: '1rem',
49
+ padding: '0.75rem 1rem',
50
+ backgroundColor: '#fff',
51
+ borderBottom: '1px solid #e9ecef',
52
+ flexWrap: 'wrap',
53
+ alignItems: 'center',
54
+ },
55
+ toolbarGroup: {
56
+ display: 'flex',
57
+ gap: '0.5rem',
58
+ alignItems: 'center',
59
+ },
60
+ toolbarLabel: {
61
+ fontSize: '0.875rem',
62
+ color: '#666',
63
+ },
64
+ select: {
65
+ padding: '0.5rem',
66
+ borderRadius: '4px',
67
+ border: '1px solid #ddd',
68
+ fontSize: '0.875rem',
69
+ backgroundColor: 'white',
70
+ },
71
+ addButton: {
72
+ padding: '0.5rem 1rem',
73
+ backgroundColor: '#007bff',
74
+ color: 'white',
75
+ border: 'none',
76
+ borderRadius: '4px',
77
+ cursor: 'pointer',
78
+ fontSize: '0.875rem',
79
+ display: 'flex',
80
+ alignItems: 'center',
81
+ gap: '0.25rem',
82
+ },
83
+ content: {
84
+ flex: 1,
85
+ overflow: 'auto',
86
+ },
87
+ pageContainer: {
88
+ maxWidth: '1200px',
89
+ margin: '0 auto',
90
+ },
91
+ emptyState: {
92
+ textAlign: 'center',
93
+ padding: '4rem 2rem',
94
+ color: '#666',
95
+ backgroundColor: '#f9f9f9',
96
+ borderRadius: '8px',
97
+ border: '2px dashed #ddd',
98
+ margin: '2rem',
99
+ },
100
+ emptyStateTitle: {
101
+ fontSize: '1.5rem',
102
+ marginBottom: '1rem',
103
+ color: '#333',
104
+ },
105
+ emptyStateText: {
106
+ marginBottom: '1.5rem',
107
+ },
108
+ // Options panel styles
109
+ optionsPanel: {
110
+ padding: '1.5rem',
111
+ maxWidth: '600px',
112
+ margin: '0 auto',
113
+ },
114
+ optionGroup: {
115
+ marginBottom: '1.5rem',
116
+ },
117
+ optionLabel: {
118
+ display: 'block',
119
+ fontSize: '0.875rem',
120
+ fontWeight: 500,
121
+ marginBottom: '0.5rem',
122
+ color: '#333',
123
+ },
124
+ optionInput: {
125
+ width: '100%',
126
+ padding: '0.5rem',
127
+ borderRadius: '4px',
128
+ border: '1px solid #ddd',
129
+ fontSize: '0.875rem',
130
+ },
131
+ optionRow: {
132
+ display: 'flex',
133
+ gap: '1rem',
134
+ alignItems: 'center',
135
+ },
136
+ colorInput: {
137
+ width: '60px',
138
+ height: '36px',
139
+ padding: '2px',
140
+ borderRadius: '4px',
141
+ border: '1px solid #ddd',
142
+ cursor: 'pointer',
143
+ },
144
+ noSelection: {
145
+ textAlign: 'center',
146
+ padding: '4rem 2rem',
147
+ color: '#999',
148
+ },
149
+ // Layout picker
150
+ layoutPicker: {
151
+ position: 'fixed',
152
+ top: 0,
153
+ left: 0,
154
+ right: 0,
155
+ bottom: 0,
156
+ backgroundColor: 'rgba(0,0,0,0.5)',
157
+ display: 'flex',
158
+ alignItems: 'center',
159
+ justifyContent: 'center',
160
+ zIndex: 1000,
161
+ },
162
+ layoutPickerContent: {
163
+ backgroundColor: 'white',
164
+ borderRadius: '8px',
165
+ padding: '1.5rem',
166
+ maxWidth: '600px',
167
+ width: '90%',
168
+ maxHeight: '80vh',
169
+ overflow: 'auto',
170
+ },
171
+ layoutPickerTitle: {
172
+ fontSize: '1.25rem',
173
+ marginBottom: '1rem',
174
+ fontWeight: 600,
175
+ },
176
+ layoutGrid: {
177
+ display: 'grid',
178
+ gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
179
+ gap: '1rem',
180
+ },
181
+ layoutCard: {
182
+ padding: '1rem',
183
+ border: '1px solid #ddd',
184
+ borderRadius: '8px',
185
+ cursor: 'pointer',
186
+ textAlign: 'center',
187
+ transition: 'border-color 0.2s, box-shadow 0.2s',
188
+ },
189
+ layoutCardHover: {
190
+ borderColor: '#007bff',
191
+ boxShadow: '0 0 0 3px rgba(0, 123, 255, 0.1)',
192
+ },
193
+ layoutCardIcon: {
194
+ fontSize: '2rem',
195
+ marginBottom: '0.5rem',
196
+ },
197
+ layoutCardName: {
198
+ fontWeight: 500,
199
+ marginBottom: '0.25rem',
200
+ },
201
+ layoutCardDesc: {
202
+ fontSize: '0.75rem',
203
+ color: '#666',
204
+ },
205
+ };
206
+ function TabButton({ label, isActive, onClick }) {
207
+ const [isHovered, setIsHovered] = (0, react_1.useState)(false);
208
+ return ((0, jsx_runtime_1.jsx)("button", { onClick: onClick, style: {
209
+ ...styles.tab,
210
+ ...(isActive ? styles.tabActive : {}),
211
+ ...(isHovered && !isActive ? styles.tabHover : {}),
212
+ }, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: label }));
213
+ }
214
+ function LayoutPicker({ onSelect, onClose }) {
215
+ const layouts = (0, layouts_1.getAllLayouts)();
216
+ const [hoveredLayout, setHoveredLayout] = (0, react_1.useState)(null);
217
+ return ((0, jsx_runtime_1.jsx)("div", { style: styles.layoutPicker, onClick: onClose, children: (0, jsx_runtime_1.jsxs)("div", { style: styles.layoutPickerContent, onClick: (e) => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { style: styles.layoutPickerTitle, children: "Choisir un layout" }), (0, jsx_runtime_1.jsx)("div", { style: styles.layoutGrid, children: layouts.map((layout) => ((0, jsx_runtime_1.jsxs)("div", { style: {
218
+ ...styles.layoutCard,
219
+ ...(hoveredLayout === layout.type ? styles.layoutCardHover : {}),
220
+ }, onClick: () => onSelect(layout.type), onMouseEnter: () => setHoveredLayout(layout.type), onMouseLeave: () => setHoveredLayout(null), children: [(0, jsx_runtime_1.jsx)("div", { style: styles.layoutCardIcon, children: layout.icon || '📄' }), (0, jsx_runtime_1.jsx)("div", { style: styles.layoutCardName, children: layout.name }), (0, jsx_runtime_1.jsx)("div", { style: styles.layoutCardDesc, children: layout.description })] }, layout.type))) }), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: '1rem', textAlign: 'right' }, children: (0, jsx_runtime_1.jsx)("button", { onClick: onClose, style: {
221
+ padding: '0.5rem 1rem',
222
+ border: '1px solid #ddd',
223
+ borderRadius: '4px',
224
+ backgroundColor: 'white',
225
+ cursor: 'pointer',
226
+ }, children: "Annuler" }) })] }) }));
227
+ }
228
+ // ============================================
229
+ // Section Options Panel
230
+ // ============================================
231
+ function SectionOptionsPanel() {
232
+ const { selectedSectionId, getSelectedSection, updateSectionSettings, updateSection } = (0, PageContext_1.usePageContext)();
233
+ const section = getSelectedSection();
234
+ if (!selectedSectionId || !section) {
235
+ return ((0, jsx_runtime_1.jsx)("div", { style: styles.noSelection, children: (0, jsx_runtime_1.jsx)("p", { children: "Cliquez sur une section pour modifier ses options" }) }));
236
+ }
237
+ const handleChange = (key, value) => {
238
+ updateSectionSettings(selectedSectionId, { [key]: value });
239
+ };
240
+ // Helper to update content fields
241
+ const handleContentChange = (key, value) => {
242
+ const newContent = { ...section.content, [key]: value };
243
+ updateSection(selectedSectionId, newContent);
244
+ };
245
+ // Type-safe content access
246
+ const content = section.content;
247
+ return ((0, jsx_runtime_1.jsxs)("div", { style: styles.optionsPanel, children: [(0, jsx_runtime_1.jsx)("h3", { style: { marginBottom: '1.5rem', fontSize: '1.125rem' }, children: "Options de la section" }), (0, jsx_runtime_1.jsxs)("div", { style: styles.optionGroup, children: [(0, jsx_runtime_1.jsx)("label", { style: styles.optionLabel, children: "Type de layout" }), (0, jsx_runtime_1.jsx)("div", { style: {
248
+ padding: '0.5rem',
249
+ backgroundColor: '#f8f9fa',
250
+ borderRadius: '4px',
251
+ fontSize: '0.875rem',
252
+ color: '#666'
253
+ }, children: section.layoutType })] }), section.layoutType === 'ogilvy' && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: styles.optionGroup, children: [(0, jsx_runtime_1.jsx)("label", { style: styles.optionLabel, children: "Colonnes" }), (0, jsx_runtime_1.jsxs)("select", { value: content.columns || 2, onChange: (e) => handleContentChange('columns', Number(e.target.value)), style: styles.optionInput, children: [(0, jsx_runtime_1.jsx)("option", { value: 2, children: "2 colonnes" }), (0, jsx_runtime_1.jsx)("option", { value: 3, children: "3 colonnes" })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: styles.optionGroup, children: [(0, jsx_runtime_1.jsx)("label", { style: styles.optionLabel, children: "Hauteur (lignes)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", value: content.columnLines || '', onChange: (e) => handleContentChange('columnLines', e.target.value ? Number(e.target.value) : undefined), placeholder: "auto", min: 5, max: 100, style: styles.optionInput })] }), (0, jsx_runtime_1.jsx)("div", { style: styles.optionGroup, children: (0, jsx_runtime_1.jsxs)("label", { style: { ...styles.optionLabel, display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: content.dropCap?.enabled || false, onChange: (e) => handleContentChange('dropCap', {
254
+ ...(content.dropCap || {}),
255
+ enabled: e.target.checked
256
+ }) }), "Lettrine"] }) }), (0, jsx_runtime_1.jsx)("div", { style: styles.optionGroup, children: (0, jsx_runtime_1.jsxs)("label", { style: { ...styles.optionLabel, display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: content.legendAsterisk || false, onChange: (e) => handleContentChange('legendAsterisk', e.target.checked) }), "Ast\u00E9risque (*)"] }) })] })), (0, jsx_runtime_1.jsx)("hr", { style: { margin: '1.5rem 0', border: 'none', borderTop: '1px solid #e9ecef' } }), (0, jsx_runtime_1.jsxs)("div", { style: styles.optionGroup, children: [(0, jsx_runtime_1.jsx)("label", { style: styles.optionLabel, children: "Couleur de fond" }), (0, jsx_runtime_1.jsxs)("div", { style: styles.optionRow, children: [(0, jsx_runtime_1.jsx)("input", { type: "color", value: section.backgroundColor || '#ffffff', onChange: (e) => handleChange('backgroundColor', e.target.value), style: styles.colorInput }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: section.backgroundColor || '', onChange: (e) => handleChange('backgroundColor', e.target.value), placeholder: "transparent", style: { ...styles.optionInput, flex: 1 } }), (0, jsx_runtime_1.jsx)("button", { onClick: () => handleChange('backgroundColor', undefined), style: {
257
+ padding: '0.5rem',
258
+ border: '1px solid #ddd',
259
+ borderRadius: '4px',
260
+ backgroundColor: 'white',
261
+ cursor: 'pointer',
262
+ fontSize: '0.75rem',
263
+ }, children: "Reset" })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: styles.optionGroup, children: [(0, jsx_runtime_1.jsx)("label", { style: styles.optionLabel, children: "Padding" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: section.padding || '', onChange: (e) => handleChange('padding', e.target.value), placeholder: "ex: 1rem, 20px, 10px 20px", style: styles.optionInput })] }), (0, jsx_runtime_1.jsxs)("div", { style: styles.optionGroup, children: [(0, jsx_runtime_1.jsx)("label", { style: styles.optionLabel, children: "Classe CSS" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: section.className || '', onChange: (e) => handleChange('className', e.target.value), placeholder: "ex: my-custom-class", style: styles.optionInput })] })] }));
264
+ }
265
+ // ============================================
266
+ // Page Editor Inner (with context)
267
+ // ============================================
268
+ function PageEditorInner() {
269
+ const { document, isEditing, selectedSectionId, setFormat, addSection, selectSection, } = (0, PageContext_1.usePageContext)();
270
+ const [activeTab, setActiveTab] = (0, react_1.useState)('edition');
271
+ const [showLayoutPicker, setShowLayoutPicker] = (0, react_1.useState)(false);
272
+ const handleAddSection = (0, react_1.useCallback)((layoutType) => {
273
+ const defaultContent = (0, layouts_1.getLayoutDefaultContent)(layoutType);
274
+ if (defaultContent) {
275
+ addSection(layoutType, defaultContent);
276
+ }
277
+ setShowLayoutPicker(false);
278
+ }, [addSection]);
279
+ const handleFormatChange = (0, react_1.useCallback)((e) => {
280
+ setFormat(e.target.value);
281
+ }, [setFormat]);
282
+ // Auto-select first section when switching to options tab
283
+ (0, react_1.useEffect)(() => {
284
+ if (activeTab === 'options' && !selectedSectionId && document.sections.length > 0) {
285
+ selectSection(document.sections[0].id);
286
+ }
287
+ }, [activeTab, selectedSectionId, document.sections, selectSection]);
288
+ const isPreviewMode = activeTab === 'preview';
289
+ return ((0, jsx_runtime_1.jsxs)("div", { style: styles.container, children: [(0, jsx_runtime_1.jsxs)("div", { style: styles.tabBar, children: [(0, jsx_runtime_1.jsx)(TabButton, { label: "\u00C9dition", isActive: activeTab === 'edition', onClick: () => setActiveTab('edition') }), (0, jsx_runtime_1.jsx)(TabButton, { label: "Pr\u00E9visualisation", isActive: activeTab === 'preview', onClick: () => setActiveTab('preview') }), (0, jsx_runtime_1.jsx)(TabButton, { label: "Options", isActive: activeTab === 'options', onClick: () => setActiveTab('options') })] }), activeTab === 'edition' && isEditing && ((0, jsx_runtime_1.jsxs)("div", { style: styles.toolbar, children: [(0, jsx_runtime_1.jsxs)("div", { style: styles.toolbarGroup, children: [(0, jsx_runtime_1.jsx)("span", { style: styles.toolbarLabel, children: "Format:" }), (0, jsx_runtime_1.jsxs)("select", { value: document.format, onChange: handleFormatChange, style: styles.select, children: [(0, jsx_runtime_1.jsx)("option", { value: "web", children: "Web (scroll infini)" }), (0, jsx_runtime_1.jsx)("option", { value: "print", children: "Print (A4, Letter...)" }), (0, jsx_runtime_1.jsx)("option", { value: "video", children: "Video / Pr\u00E9sentation" })] })] }), document.format === 'print' && ((0, jsx_runtime_1.jsxs)("div", { style: styles.toolbarGroup, children: [(0, jsx_runtime_1.jsx)("span", { style: styles.toolbarLabel, children: "Taille:" }), (0, jsx_runtime_1.jsx)("select", { style: styles.select, children: Object.entries(page_1.PRINT_PRESETS).map(([key, preset]) => ((0, jsx_runtime_1.jsx)("option", { value: key, children: preset.name }, key))) })] })), document.format === 'video' && ((0, jsx_runtime_1.jsxs)("div", { style: styles.toolbarGroup, children: [(0, jsx_runtime_1.jsx)("span", { style: styles.toolbarLabel, children: "Taille:" }), (0, jsx_runtime_1.jsx)("select", { style: styles.select, children: Object.entries(page_1.VIDEO_PRESETS).map(([key, preset]) => ((0, jsx_runtime_1.jsx)("option", { value: key, children: preset.name }, key))) })] })), (0, jsx_runtime_1.jsx)("div", { style: { flex: 1 } }), (0, jsx_runtime_1.jsx)("button", { style: styles.addButton, onClick: () => setShowLayoutPicker(true), children: "+ Ajouter une section" })] })), (0, jsx_runtime_1.jsx)("div", { style: styles.content, children: activeTab === 'options' ? ((0, jsx_runtime_1.jsx)(SectionOptionsPanel, {})) : ((0, jsx_runtime_1.jsx)("div", { style: styles.pageContainer, children: document.sections.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { style: styles.emptyState, children: [(0, jsx_runtime_1.jsx)("div", { style: styles.emptyStateTitle, children: "Page vide" }), (0, jsx_runtime_1.jsx)("div", { style: styles.emptyStateText, children: "Commencez par ajouter une section \u00E0 votre page" }), isEditing && activeTab === 'edition' && ((0, jsx_runtime_1.jsx)("button", { style: styles.addButton, onClick: () => setShowLayoutPicker(true), children: "+ Ajouter une section" }))] })) : (document.sections.map((section, index) => ((0, jsx_runtime_1.jsx)(Section_1.SectionComponent, { section: section, index: index, totalSections: document.sections.length, isPreviewMode: isPreviewMode }, section.id)))) })) }), showLayoutPicker && ((0, jsx_runtime_1.jsx)(LayoutPicker, { onSelect: handleAddSection, onClose: () => setShowLayoutPicker(false) }))] }));
290
+ }
291
+ function PageEditor({ initialDocument, onChange, className, isEditing = true, }) {
292
+ return ((0, jsx_runtime_1.jsx)(PageContext_1.PageProvider, { initialDocument: initialDocument, isEditing: isEditing, onChange: onChange, children: (0, jsx_runtime_1.jsx)("div", { className: className, style: { height: '100%' }, children: (0, jsx_runtime_1.jsx)(PageEditorInner, {}) }) }));
293
+ }
294
+ exports.default = PageEditor;
@@ -0,0 +1,8 @@
1
+ import { PageDocument } from '../types/page';
2
+ export interface PageViewerProps {
3
+ document: PageDocument;
4
+ className?: string;
5
+ }
6
+ export declare function PageViewer({ document, className }: PageViewerProps): import("react/jsx-runtime").JSX.Element;
7
+ export default PageViewer;
8
+ //# sourceMappingURL=PageViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageViewer.d.ts","sourceRoot":"","sources":["../../src/components/PageViewer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAiE5C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,eAAe,2CAQlE;AAED,eAAe,UAAU,CAAA"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PageViewer = PageViewer;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const PageContext_1 = require("../context/PageContext");
7
+ const Section_1 = require("./Section");
8
+ const layouts_1 = require("../layouts");
9
+ // Initialize layouts on module load
10
+ (0, layouts_1.initializeLayouts)();
11
+ // ============================================
12
+ // Styles
13
+ // ============================================
14
+ const styles = {
15
+ container: {
16
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
17
+ },
18
+ pageContainer: {
19
+ padding: '2rem',
20
+ maxWidth: '1200px',
21
+ margin: '0 auto',
22
+ },
23
+ emptyState: {
24
+ textAlign: 'center',
25
+ padding: '4rem 2rem',
26
+ color: '#666',
27
+ },
28
+ };
29
+ function PageViewerInner({ document }) {
30
+ if (document.sections.length === 0) {
31
+ return ((0, jsx_runtime_1.jsx)("div", { style: styles.pageContainer, children: (0, jsx_runtime_1.jsx)("div", { style: styles.emptyState, children: "Cette page est vide" }) }));
32
+ }
33
+ return ((0, jsx_runtime_1.jsx)("div", { style: styles.pageContainer, children: document.sections.map((section, index) => ((0, jsx_runtime_1.jsx)(Section_1.SectionComponent, { section: section, index: index, totalSections: document.sections.length }, section.id))) }));
34
+ }
35
+ function PageViewer({ document, className }) {
36
+ return ((0, jsx_runtime_1.jsx)(PageContext_1.PageProvider, { initialDocument: document, isEditing: false, children: (0, jsx_runtime_1.jsx)("div", { style: styles.container, className: className, children: (0, jsx_runtime_1.jsx)(PageViewerInner, { document: document }) }) }));
37
+ }
38
+ exports.default = PageViewer;
@@ -10,6 +10,10 @@ export interface RichTextEditorProps {
10
10
  placeholder?: string;
11
11
  className?: string;
12
12
  minHeight?: string;
13
+ /** Number of columns for text flow (newspaper-style) */
14
+ columns?: 1 | 2 | 3;
15
+ /** If true, editor grows to fit content (no scroll). If false, fixed height with scroll. */
16
+ autoGrow?: boolean;
13
17
  }
14
- export declare function RichTextEditor({ initialContent, onChange, onAIRequest, placeholder, className, minHeight }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function RichTextEditor({ initialContent, onChange, onAIRequest, placeholder, className, minHeight, columns, autoGrow }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
15
19
  //# sourceMappingURL=RichTextEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../src/components/RichTextEditor.tsx"],"names":[],"mappings":"AAkCA,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAA;QAC1C,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAqKD,wBAAgB,cAAc,CAAC,EAC7B,cAAmB,EACnB,QAAQ,EACR,WAAW,EACX,WAAqC,EACrC,SAAc,EACd,SAAmB,EACpB,EAAE,mBAAmB,2CAkJrB"}
1
+ {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../src/components/RichTextEditor.tsx"],"names":[],"mappings":"AAkCA,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAA;QAC1C,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACnB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAqKD,wBAAgB,cAAc,CAAC,EAC7B,cAAmB,EACnB,QAAQ,EACR,WAAW,EACX,WAAqC,EACrC,SAAc,EACd,SAAmB,EACnB,OAAW,EACX,QAAe,EAChB,EAAE,mBAAmB,2CA6JrB"}
@@ -211,7 +211,7 @@ function EditorRefPlugin({ editorRef }) {
211
211
  }, [editor, editorRef]);
212
212
  return null;
213
213
  }
214
- function RichTextEditor({ initialContent = '', onChange, onAIRequest, placeholder = 'Commencez à écrire...', className = '', minHeight = '300px' }) {
214
+ function RichTextEditor({ initialContent = '', onChange, onAIRequest, placeholder = 'Commencez à écrire...', className = '', minHeight = '300px', columns = 1, autoGrow = true }) {
215
215
  const editorRef = react_1.default.useRef(null);
216
216
  const [isLoading, setIsLoading] = react_1.default.useState(false);
217
217
  const [isFullscreen, setIsFullscreen] = react_1.default.useState(false);
@@ -286,5 +286,14 @@ function RichTextEditor({ initialContent = '', onChange, onAIRequest, placeholde
286
286
  const fullscreenClasses = isFullscreen
287
287
  ? 'fixed inset-0 z-50'
288
288
  : '';
289
- return ((0, jsx_runtime_1.jsx)(EditorModeContext_1.EditorModeProvider, { isViewer: false, children: (0, jsx_runtime_1.jsxs)("div", { className: `border border-gray-200 rounded-lg bg-white flex flex-col overflow-hidden ${fullscreenClasses} ${className}`, style: minHeight && !isFullscreen ? { height: minHeight } : {}, children: [(0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: editorStyles } }), (0, jsx_runtime_1.jsxs)(LexicalComposer_1.LexicalComposer, { initialConfig: getEditorConfig(initialContent), children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-shrink-0 bg-white border-b border-gray-200", children: (0, jsx_runtime_1.jsx)(EditorToolbar_1.EditorToolbar, { onAIAction: handleAIAction, isLoading: isLoading, isFullscreen: isFullscreen, onToggleFullscreen: toggleFullscreen }) }), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex-1 overflow-y-auto", children: [(0, jsx_runtime_1.jsx)(LexicalRichTextPlugin_1.RichTextPlugin, { contentEditable: (0, jsx_runtime_1.jsx)(LexicalContentEditable_1.ContentEditable, { className: "outline-none p-4 text-gray-900" }), placeholder: (0, jsx_runtime_1.jsx)("div", { className: "absolute top-4 left-4 text-gray-400 pointer-events-none", children: placeholder }), ErrorBoundary: LexicalErrorBoundary_1.LexicalErrorBoundary }), (0, jsx_runtime_1.jsx)(LexicalHistoryPlugin_1.HistoryPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalListPlugin_1.ListPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalLinkPlugin_1.LinkPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalOnChangePlugin_1.OnChangePlugin, { onChange: handleChange }), (0, jsx_runtime_1.jsx)(InitialContentPlugin, { content: initialContent }), (0, jsx_runtime_1.jsx)(EditorRefPlugin, { editorRef: editorRef }), (0, jsx_runtime_1.jsx)(InsertObjectPlugin_1.InsertObjectPlugin, {}), (0, jsx_runtime_1.jsx)(ImageLinkPlugin_1.ImageLinkPlugin, {}), (0, jsx_runtime_1.jsx)(LinkPlugin_1.SimpleLinkPlugin, {}), isLoading && ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 bg-white/80 flex items-center justify-center z-10", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-blue-600", children: [(0, jsx_runtime_1.jsx)("span", { className: "material-icons animate-spin", children: "sync" }), (0, jsx_runtime_1.jsx)("span", { children: "L'IA travaille..." })] }) }))] })] })] }) }));
289
+ // Container style: autoGrow uses minHeight, fixed uses height
290
+ const containerStyle = minHeight && !isFullscreen
291
+ ? autoGrow
292
+ ? { minHeight }
293
+ : { height: minHeight }
294
+ : {};
295
+ return ((0, jsx_runtime_1.jsx)(EditorModeContext_1.EditorModeProvider, { isViewer: false, children: (0, jsx_runtime_1.jsxs)("div", { className: `border border-gray-200 rounded-lg bg-white flex flex-col ${autoGrow ? '' : 'overflow-hidden'} ${fullscreenClasses} ${className}`, style: containerStyle, children: [(0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: editorStyles } }), (0, jsx_runtime_1.jsxs)(LexicalComposer_1.LexicalComposer, { initialConfig: getEditorConfig(initialContent), children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-shrink-0 bg-white border-b border-gray-200", children: (0, jsx_runtime_1.jsx)(EditorToolbar_1.EditorToolbar, { onAIAction: handleAIAction, isLoading: isLoading, isFullscreen: isFullscreen, onToggleFullscreen: toggleFullscreen }) }), (0, jsx_runtime_1.jsxs)("div", { className: `relative flex-1 ${autoGrow ? '' : 'overflow-y-auto'}`, children: [(0, jsx_runtime_1.jsx)(LexicalRichTextPlugin_1.RichTextPlugin, { contentEditable: (0, jsx_runtime_1.jsx)(LexicalContentEditable_1.ContentEditable, { className: "outline-none p-4 text-gray-900", style: columns > 1 ? {
296
+ columnCount: columns,
297
+ columnGap: '2rem',
298
+ } : undefined }), placeholder: (0, jsx_runtime_1.jsx)("div", { className: "absolute top-4 left-4 text-gray-400 pointer-events-none", children: placeholder }), ErrorBoundary: LexicalErrorBoundary_1.LexicalErrorBoundary }), (0, jsx_runtime_1.jsx)(LexicalHistoryPlugin_1.HistoryPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalListPlugin_1.ListPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalLinkPlugin_1.LinkPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalOnChangePlugin_1.OnChangePlugin, { onChange: handleChange }), (0, jsx_runtime_1.jsx)(InitialContentPlugin, { content: initialContent }), (0, jsx_runtime_1.jsx)(EditorRefPlugin, { editorRef: editorRef }), (0, jsx_runtime_1.jsx)(InsertObjectPlugin_1.InsertObjectPlugin, {}), (0, jsx_runtime_1.jsx)(ImageLinkPlugin_1.ImageLinkPlugin, {}), (0, jsx_runtime_1.jsx)(LinkPlugin_1.SimpleLinkPlugin, {}), isLoading && ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 bg-white/80 flex items-center justify-center z-10", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-blue-600", children: [(0, jsx_runtime_1.jsx)("span", { className: "material-icons animate-spin", children: "sync" }), (0, jsx_runtime_1.jsx)("span", { children: "L'IA travaille..." })] }) }))] })] })] }) }));
290
299
  }
@@ -1,6 +1,8 @@
1
1
  export interface RichTextViewerProps {
2
2
  content?: string;
3
3
  className?: string;
4
+ /** Number of columns for text flow (newspaper-style) */
5
+ columns?: 1 | 2 | 3;
4
6
  }
5
- export declare function RichTextViewer({ content, className }: RichTextViewerProps): import("react/jsx-runtime").JSX.Element | null;
7
+ export declare function RichTextViewer({ content, className, columns }: RichTextViewerProps): import("react/jsx-runtime").JSX.Element | null;
6
8
  //# sourceMappingURL=RichTextViewer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextViewer.d.ts","sourceRoot":"","sources":["../../src/components/RichTextViewer.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA4ID,wBAAgB,cAAc,CAAC,EAC7B,OAAY,EACZ,SAAc,EACf,EAAE,mBAAmB,kDA8BrB"}
1
+ {"version":3,"file":"RichTextViewer.d.ts","sourceRoot":"","sources":["../../src/components/RichTextViewer.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CACpB;AA4ID,wBAAgB,cAAc,CAAC,EAC7B,OAAY,EACZ,SAAc,EACd,OAAW,EACZ,EAAE,mBAAmB,kDAoCrB"}
@@ -153,10 +153,15 @@ function ContentLoaderPlugin({ content }) {
153
153
  }, [editor, content]);
154
154
  return null;
155
155
  }
156
- function RichTextViewer({ content = '', className = '' }) {
156
+ function RichTextViewer({ content = '', className = '', columns = 1 }) {
157
157
  // Don't render anything if no content
158
158
  if (!content) {
159
159
  return null;
160
160
  }
161
- return ((0, jsx_runtime_1.jsx)(EditorModeContext_1.EditorModeProvider, { isViewer: true, children: (0, jsx_runtime_1.jsxs)("div", { className: className, children: [(0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: viewerStyles } }), (0, jsx_runtime_1.jsxs)(LexicalComposer_1.LexicalComposer, { initialConfig: getViewerConfig(), children: [(0, jsx_runtime_1.jsx)(LexicalRichTextPlugin_1.RichTextPlugin, { contentEditable: (0, jsx_runtime_1.jsx)(LexicalContentEditable_1.ContentEditable, { className: "outline-none text-gray-900", style: { cursor: 'default' } }), placeholder: null, ErrorBoundary: LexicalErrorBoundary_1.LexicalErrorBoundary }), (0, jsx_runtime_1.jsx)(LexicalListPlugin_1.ListPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalLinkPlugin_1.LinkPlugin, {}), (0, jsx_runtime_1.jsx)(ContentLoaderPlugin, { content: content }), (0, jsx_runtime_1.jsx)(ImageLinkPlugin_1.ImageLinkPlugin, {}), (0, jsx_runtime_1.jsx)(LinkPlugin_1.SimpleLinkPlugin, {})] })] }) }));
161
+ const columnStyle = columns > 1 ? {
162
+ columnCount: columns,
163
+ columnGap: '2rem',
164
+ cursor: 'default',
165
+ } : { cursor: 'default' };
166
+ return ((0, jsx_runtime_1.jsx)(EditorModeContext_1.EditorModeProvider, { isViewer: true, children: (0, jsx_runtime_1.jsxs)("div", { className: className, children: [(0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: viewerStyles } }), (0, jsx_runtime_1.jsxs)(LexicalComposer_1.LexicalComposer, { initialConfig: getViewerConfig(), children: [(0, jsx_runtime_1.jsx)(LexicalRichTextPlugin_1.RichTextPlugin, { contentEditable: (0, jsx_runtime_1.jsx)(LexicalContentEditable_1.ContentEditable, { className: "outline-none text-gray-900", style: columnStyle }), placeholder: null, ErrorBoundary: LexicalErrorBoundary_1.LexicalErrorBoundary }), (0, jsx_runtime_1.jsx)(LexicalListPlugin_1.ListPlugin, {}), (0, jsx_runtime_1.jsx)(LexicalLinkPlugin_1.LinkPlugin, {}), (0, jsx_runtime_1.jsx)(ContentLoaderPlugin, { content: content }), (0, jsx_runtime_1.jsx)(ImageLinkPlugin_1.ImageLinkPlugin, {}), (0, jsx_runtime_1.jsx)(LinkPlugin_1.SimpleLinkPlugin, {})] })] }) }));
162
167
  }
@@ -0,0 +1,10 @@
1
+ import { Section as SectionType } from '../types/page';
2
+ interface SectionComponentProps {
3
+ section: SectionType;
4
+ index: number;
5
+ totalSections: number;
6
+ isPreviewMode?: boolean;
7
+ }
8
+ export declare function SectionComponent({ section, index, totalSections, isPreviewMode }: SectionComponentProps): import("react/jsx-runtime").JSX.Element;
9
+ export default SectionComponent;
10
+ //# sourceMappingURL=Section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Section.d.ts","sourceRoot":"","sources":["../../src/components/Section.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAA;AAkKtD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,WAAW,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,aAAqB,EAAE,EAAE,qBAAqB,2CA+D/G;AAED,eAAe,gBAAgB,CAAA"}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.SectionComponent = SectionComponent;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const layouts_1 = require("../layouts");
8
+ const PageContext_1 = require("../context/PageContext");
9
+ // ============================================
10
+ // Styles
11
+ // ============================================
12
+ const styles = {
13
+ container: {
14
+ position: 'relative',
15
+ },
16
+ wrapper: {
17
+ border: '1px solid transparent',
18
+ transition: 'border-color 0.2s, box-shadow 0.2s',
19
+ },
20
+ wrapperHover: {
21
+ borderColor: '#007bff',
22
+ boxShadow: '0 0 0 3px rgba(0, 123, 255, 0.1)',
23
+ },
24
+ wrapperSelected: {
25
+ borderColor: '#007bff',
26
+ boxShadow: '0 0 0 3px rgba(0, 123, 255, 0.2)',
27
+ },
28
+ toolbar: {
29
+ position: 'absolute',
30
+ top: '-40px',
31
+ right: '0',
32
+ display: 'flex',
33
+ gap: '0.25rem',
34
+ backgroundColor: 'white',
35
+ padding: '0.25rem',
36
+ borderRadius: '4px',
37
+ boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
38
+ zIndex: 10,
39
+ },
40
+ toolbarButton: {
41
+ padding: '0.5rem',
42
+ border: 'none',
43
+ borderRadius: '4px',
44
+ backgroundColor: 'transparent',
45
+ cursor: 'pointer',
46
+ fontSize: '1rem',
47
+ display: 'flex',
48
+ alignItems: 'center',
49
+ justifyContent: 'center',
50
+ minWidth: '32px',
51
+ transition: 'background-color 0.2s',
52
+ },
53
+ toolbarButtonHover: {
54
+ backgroundColor: '#f0f0f0',
55
+ },
56
+ toolbarButtonDanger: {
57
+ color: '#dc3545',
58
+ },
59
+ dragHandle: {
60
+ cursor: 'grab',
61
+ padding: '0.5rem',
62
+ color: '#999',
63
+ },
64
+ emptyLayout: {
65
+ padding: '2rem',
66
+ textAlign: 'center',
67
+ color: '#999',
68
+ backgroundColor: '#f9f9f9',
69
+ borderRadius: '4px',
70
+ border: '1px dashed #ddd',
71
+ },
72
+ };
73
+ function ToolbarButton({ onClick, title, children, danger, disabled }) {
74
+ const [isHovered, setIsHovered] = (0, react_1.useState)(false);
75
+ return ((0, jsx_runtime_1.jsx)("button", { onClick: onClick, title: title, disabled: disabled, style: {
76
+ ...styles.toolbarButton,
77
+ ...(isHovered ? styles.toolbarButtonHover : {}),
78
+ ...(danger ? styles.toolbarButtonDanger : {}),
79
+ opacity: disabled ? 0.5 : 1,
80
+ cursor: disabled ? 'not-allowed' : 'pointer',
81
+ }, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: children }));
82
+ }
83
+ function SectionToolbar({ sectionId, canMoveUp, canMoveDown }) {
84
+ const { moveSection, deleteSection, duplicateSection } = (0, PageContext_1.usePageContext)();
85
+ return ((0, jsx_runtime_1.jsxs)("div", { style: styles.toolbar, children: [(0, jsx_runtime_1.jsx)("div", { style: styles.dragHandle, title: "Glisser pour d\u00E9placer", children: "\u22EE\u22EE" }), (0, jsx_runtime_1.jsx)(ToolbarButton, { onClick: () => moveSection(sectionId, 'up'), title: "Monter", disabled: !canMoveUp, children: "\u2191" }), (0, jsx_runtime_1.jsx)(ToolbarButton, { onClick: () => moveSection(sectionId, 'down'), title: "Descendre", disabled: !canMoveDown, children: "\u2193" }), (0, jsx_runtime_1.jsx)(ToolbarButton, { onClick: () => duplicateSection(sectionId), title: "Dupliquer", children: "\u29C9" }), (0, jsx_runtime_1.jsx)(ToolbarButton, { onClick: () => {
86
+ if (window.confirm('Supprimer cette section ?')) {
87
+ deleteSection(sectionId);
88
+ }
89
+ }, title: "Supprimer", danger: true, children: "\u00D7" })] }));
90
+ }
91
+ function SectionComponent({ section, index, totalSections, isPreviewMode = false }) {
92
+ const { isEditing, updateSection, selectedSectionId, selectSection } = (0, PageContext_1.usePageContext)();
93
+ const [isHovered, setIsHovered] = (0, react_1.useState)(false);
94
+ const isSelected = selectedSectionId === section.id;
95
+ const showEditingUI = isEditing && !isPreviewMode;
96
+ const LayoutComponent = (0, layouts_1.getLayoutComponent)(section.layoutType);
97
+ const handleContentChange = (0, react_1.useCallback)((content) => {
98
+ updateSection(section.id, content);
99
+ }, [section.id, updateSection]);
100
+ const wrapperStyle = {
101
+ ...styles.wrapper,
102
+ ...(isHovered && showEditingUI ? styles.wrapperHover : {}),
103
+ ...(isSelected && showEditingUI ? styles.wrapperSelected : {}),
104
+ backgroundColor: section.backgroundColor || 'transparent',
105
+ padding: section.padding || 0,
106
+ };
107
+ if (!LayoutComponent) {
108
+ return ((0, jsx_runtime_1.jsx)("div", { style: styles.container, children: (0, jsx_runtime_1.jsxs)("div", { style: styles.emptyLayout, children: ["Layout \"", section.layoutType, "\" non trouv\u00E9"] }) }));
109
+ }
110
+ const handleClick = () => {
111
+ if (showEditingUI) {
112
+ selectSection(section.id);
113
+ }
114
+ };
115
+ return ((0, jsx_runtime_1.jsxs)("div", { style: styles.container, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onClick: handleClick, children: [showEditingUI && isHovered && ((0, jsx_runtime_1.jsx)(SectionToolbar, { sectionId: section.id, canMoveUp: index > 0, canMoveDown: index < totalSections - 1 })), (0, jsx_runtime_1.jsx)("div", { style: wrapperStyle, className: section.className, children: (0, jsx_runtime_1.jsx)(LayoutComponent, { section: section, isEditing: showEditingUI, onContentChange: handleContentChange }) })] }));
116
+ }
117
+ exports.default = SectionComponent;