@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.
- package/dist/components/PageEditor.d.ts +10 -0
- package/dist/components/PageEditor.d.ts.map +1 -0
- package/dist/components/PageEditor.js +294 -0
- package/dist/components/PageViewer.d.ts +8 -0
- package/dist/components/PageViewer.d.ts.map +1 -0
- package/dist/components/PageViewer.js +38 -0
- package/dist/components/RichTextEditor.d.ts +5 -1
- package/dist/components/RichTextEditor.d.ts.map +1 -1
- package/dist/components/RichTextEditor.js +11 -2
- package/dist/components/RichTextViewer.d.ts +3 -1
- package/dist/components/RichTextViewer.d.ts.map +1 -1
- package/dist/components/RichTextViewer.js +7 -2
- package/dist/components/Section.d.ts +10 -0
- package/dist/components/Section.d.ts.map +1 -0
- package/dist/components/Section.js +117 -0
- package/dist/components/SmartEditor.d.ts +58 -0
- package/dist/components/SmartEditor.d.ts.map +1 -0
- package/dist/components/SmartEditor.js +123 -0
- package/dist/context/PageContext.d.ts +35 -0
- package/dist/context/PageContext.d.ts.map +1 -0
- package/dist/context/PageContext.js +277 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -1
- package/dist/layouts/OgilvyLayout.d.ts +5 -0
- package/dist/layouts/OgilvyLayout.d.ts.map +1 -0
- package/dist/layouts/OgilvyLayout.js +301 -0
- package/dist/layouts/RichTextLayout.d.ts +7 -0
- package/dist/layouts/RichTextLayout.d.ts.map +1 -0
- package/dist/layouts/RichTextLayout.js +47 -0
- package/dist/layouts/index.d.ts +30 -0
- package/dist/layouts/index.d.ts.map +1 -0
- package/dist/layouts/index.js +71 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +20 -0
- package/dist/types/page.d.ts +151 -0
- package/dist/types/page.d.ts.map +1 -0
- package/dist/types/page.js +54 -0
- package/dist/utils/format.d.ts +71 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +190 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +20 -0
- 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,
|
|
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
|
-
|
|
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;
|
|
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
|
-
|
|
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;
|