@capytale/meta-player 0.3.4 → 0.3.5
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/package.json +3 -2
- package/src/App.tsx +1 -1
- package/src/MetaPlayer.tsx +29 -2
- package/src/features/activityData/activityDataSlice.ts +47 -12
- package/src/features/activityJS/ActivityJSProvider.tsx +13 -14
- package/src/features/activityJS/Saver.tsx +34 -24
- package/src/features/layout/layoutSlice.ts +16 -2
- package/src/features/navbar/CapytaleMenu.tsx +93 -79
- package/src/features/pedago/InstructionsEditor.tsx +50 -33
- package/src/features/pedago/PdfEditor.tsx +91 -0
- package/src/features/pedago/PedagoCommands.tsx +325 -0
- package/src/features/pedago/SharedNotesEditor.tsx +145 -0
- package/src/features/pedago/index.tsx +19 -74
- package/src/features/pedago/style.module.scss +119 -15
- package/src/index.css +6 -2
- package/src/features/pedago/AnswerSheetEditor.tsx +0 -72
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Button } from "primereact/button";
|
|
2
1
|
import { Panel } from "primereact/panel";
|
|
3
2
|
import styles from "./style.module.scss";
|
|
4
3
|
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
|
@@ -6,8 +5,6 @@ import {
|
|
|
6
5
|
selectIsGradingVisible,
|
|
7
6
|
selectOrientation,
|
|
8
7
|
selectPedagoTab,
|
|
9
|
-
toggleIsGradingVisible,
|
|
10
|
-
toggleIsPedagoVisible,
|
|
11
8
|
} from "../layout/layoutSlice";
|
|
12
9
|
|
|
13
10
|
import "@capytale/capytale-rich-text-editor/style.css";
|
|
@@ -24,9 +21,10 @@ import {
|
|
|
24
21
|
setIsMPDirty,
|
|
25
22
|
} from "../activityData/activityDataSlice";
|
|
26
23
|
import { ChangeEventHandler } from "react";
|
|
27
|
-
import settings from "../../settings";
|
|
28
24
|
import { DivProps } from "react-html-props";
|
|
29
|
-
import
|
|
25
|
+
import SharedNotesEditor from "./SharedNotesEditor";
|
|
26
|
+
import { PedagoCommands } from "./PedagoCommands";
|
|
27
|
+
import { PdfEditor } from "./PdfEditor";
|
|
30
28
|
|
|
31
29
|
const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
32
30
|
const dispatch = useAppDispatch();
|
|
@@ -60,40 +58,7 @@ const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
|
60
58
|
return (
|
|
61
59
|
// @ts-ignore - Incompatibility for props in TS
|
|
62
60
|
<div className={classNames(styles.pedago, className)} {...props}>
|
|
63
|
-
<
|
|
64
|
-
<Button
|
|
65
|
-
severity="secondary"
|
|
66
|
-
icon="pi pi-times"
|
|
67
|
-
rounded
|
|
68
|
-
text
|
|
69
|
-
aria-label="Masquer les consignes"
|
|
70
|
-
tooltip="Masquer les consignes"
|
|
71
|
-
tooltipOptions={{
|
|
72
|
-
position: "left",
|
|
73
|
-
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
74
|
-
}}
|
|
75
|
-
onClick={() => dispatch(toggleIsPedagoVisible())}
|
|
76
|
-
/>
|
|
77
|
-
{/*
|
|
78
|
-
<Button
|
|
79
|
-
rounded
|
|
80
|
-
text
|
|
81
|
-
icon="pi pi-times"
|
|
82
|
-
label="H"
|
|
83
|
-
onClick={() => {
|
|
84
|
-
dispatch(
|
|
85
|
-
setPedagoTab(
|
|
86
|
-
pedagoTab === "instructions" ? "answerSheet" : "instructions",
|
|
87
|
-
),
|
|
88
|
-
);
|
|
89
|
-
}}
|
|
90
|
-
/>
|
|
91
|
-
*/}
|
|
92
|
-
<div className={styles.pedagoSeparator}></div>
|
|
93
|
-
{(mode === "assignment" || mode === "review") && (
|
|
94
|
-
<ShowHideGradingButton />
|
|
95
|
-
)}
|
|
96
|
-
</div>
|
|
61
|
+
<PedagoCommands />
|
|
97
62
|
<div
|
|
98
63
|
className={styles.pedagoContent}
|
|
99
64
|
data-grading-visible={isGradingVisible}
|
|
@@ -101,7 +66,8 @@ const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
|
101
66
|
{!isGradingVisible && (
|
|
102
67
|
<>
|
|
103
68
|
{pedagoTab === "instructions" && <InstructionsEditor />}
|
|
104
|
-
{pedagoTab === "
|
|
69
|
+
{pedagoTab === "sharedNotes" && <SharedNotesEditor />}
|
|
70
|
+
{pedagoTab === "pdf" && <PdfEditor />}
|
|
105
71
|
</>
|
|
106
72
|
)}
|
|
107
73
|
{isGradingVisible && (
|
|
@@ -173,11 +139,21 @@ const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
|
173
139
|
size={60}
|
|
174
140
|
className={styles.pedagoPanel}
|
|
175
141
|
>
|
|
176
|
-
<Panel
|
|
142
|
+
<Panel
|
|
143
|
+
className={styles.fullSizePanel}
|
|
144
|
+
header={
|
|
145
|
+
pedagoTab === "instructions"
|
|
146
|
+
? "Consignes"
|
|
147
|
+
: pedagoTab === "pdf"
|
|
148
|
+
? "PDF"
|
|
149
|
+
: "Notes partagées"
|
|
150
|
+
}
|
|
151
|
+
>
|
|
177
152
|
{pedagoTab === "instructions" && <InstructionsEditor />}
|
|
178
|
-
{pedagoTab === "
|
|
153
|
+
{pedagoTab === "sharedNotes" && <SharedNotesEditor />}
|
|
154
|
+
{pedagoTab === "pdf" && <PdfEditor />}
|
|
179
155
|
</Panel>
|
|
180
|
-
</SplitterPanel
|
|
156
|
+
</SplitterPanel>,
|
|
181
157
|
])}
|
|
182
158
|
</Splitter>
|
|
183
159
|
)}
|
|
@@ -186,35 +162,4 @@ const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
|
186
162
|
);
|
|
187
163
|
};
|
|
188
164
|
|
|
189
|
-
const ShowHideGradingButton: React.FC = () => {
|
|
190
|
-
const dispatch = useAppDispatch();
|
|
191
|
-
const mode = useAppSelector(selectMode);
|
|
192
|
-
const hasGradingOrComments = useAppSelector(selectHasGradingOrComments);
|
|
193
|
-
const isGradingVisible = useAppSelector(selectIsGradingVisible);
|
|
194
|
-
const tooltip =
|
|
195
|
-
hasGradingOrComments || mode === "review"
|
|
196
|
-
? isGradingVisible
|
|
197
|
-
? "Masquer la notation"
|
|
198
|
-
: "Afficher la notation"
|
|
199
|
-
: "Pas de note";
|
|
200
|
-
|
|
201
|
-
return (
|
|
202
|
-
<Button
|
|
203
|
-
severity="secondary"
|
|
204
|
-
icon="pi pi-graduation-cap"
|
|
205
|
-
disabled={!(hasGradingOrComments || mode === "review")}
|
|
206
|
-
rounded
|
|
207
|
-
text={!isGradingVisible || !(hasGradingOrComments || mode === "review")}
|
|
208
|
-
aria-label={tooltip}
|
|
209
|
-
tooltip={tooltip}
|
|
210
|
-
tooltipOptions={{
|
|
211
|
-
position: "left",
|
|
212
|
-
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
213
|
-
showOnDisabled: true,
|
|
214
|
-
}}
|
|
215
|
-
onClick={() => dispatch(toggleIsGradingVisible())}
|
|
216
|
-
/>
|
|
217
|
-
);
|
|
218
|
-
};
|
|
219
|
-
|
|
220
165
|
export default Pedago;
|
|
@@ -1,29 +1,114 @@
|
|
|
1
1
|
.pedago {
|
|
2
|
-
display:
|
|
2
|
+
display: flex;
|
|
3
3
|
height: 100%;
|
|
4
4
|
width: 100%;
|
|
5
5
|
:global(.layout-horizontal) & {
|
|
6
|
-
|
|
7
|
-
grid-template-rows: 1fr;
|
|
6
|
+
flex-direction: row-reverse;
|
|
8
7
|
}
|
|
9
8
|
:global(.layout-vertical) & {
|
|
10
|
-
|
|
11
|
-
grid-template-columns: 1fr;
|
|
9
|
+
flex-direction: column;
|
|
12
10
|
}
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
.pedagoCommands {
|
|
16
14
|
flex-direction: column;
|
|
17
|
-
|
|
15
|
+
flex-shrink: 0;
|
|
18
16
|
display: flex;
|
|
19
|
-
gap: 8px;
|
|
20
17
|
background-color: var(--surface-200);
|
|
21
|
-
:global(.layout-horizontal) & {
|
|
22
|
-
|
|
23
|
-
grid-row-start: 1;
|
|
18
|
+
:global(.layout-horizontal) & > *:first-child {
|
|
19
|
+
background-color: var(--surface-300);
|
|
24
20
|
}
|
|
25
21
|
:global(.layout-vertical) & {
|
|
26
|
-
|
|
22
|
+
gap: 8px;
|
|
23
|
+
flex-direction: row;
|
|
24
|
+
align-items: center;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.pdfActions {
|
|
29
|
+
padding: 10px 0;
|
|
30
|
+
display: flex;
|
|
31
|
+
:global(.layout-horizontal) & {
|
|
32
|
+
padding-right: 9px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.pedagoHorizontalTabMenu {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
overflow-y: auto;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.pedagoHorizontalTab {
|
|
43
|
+
display: flex;
|
|
44
|
+
gap: 20px;
|
|
45
|
+
align-items: center;
|
|
46
|
+
justify-content: space-between;
|
|
47
|
+
color: var(--text-color-secondary);
|
|
48
|
+
padding: 0 16px;
|
|
49
|
+
transition: background-color 0.2s;
|
|
50
|
+
user-select: none;
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
&[data-selected="true"] {
|
|
53
|
+
background-color: var(--surface-100);
|
|
54
|
+
color: var(--text-color);
|
|
55
|
+
}
|
|
56
|
+
&:hover,
|
|
57
|
+
&:focus {
|
|
58
|
+
background-color: var(--surface-50);
|
|
59
|
+
}
|
|
60
|
+
& > span {
|
|
61
|
+
padding: 13px 0;
|
|
62
|
+
}
|
|
63
|
+
& > i {
|
|
64
|
+
padding-right: 8px;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.dropzone {
|
|
69
|
+
width: 100%;
|
|
70
|
+
height: 100%;
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: column;
|
|
73
|
+
align-items: center;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
padding: 16px;
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
outline: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.dropzoneRectangle {
|
|
81
|
+
width: 100%;
|
|
82
|
+
height: 100%;
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-direction: column;
|
|
85
|
+
align-items: center;
|
|
86
|
+
justify-content: center;
|
|
87
|
+
flex: 1;
|
|
88
|
+
padding: 20px;
|
|
89
|
+
border: 2px dashed var(--surface-100);
|
|
90
|
+
border-radius: 2px;
|
|
91
|
+
background-color: var(--surface-50);
|
|
92
|
+
color: var(--text-color-secondary);
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
outline: none;
|
|
95
|
+
transition: border-color 0.2s ease-in-out;
|
|
96
|
+
|
|
97
|
+
&[data-is-ficused="true"] {
|
|
98
|
+
border-color: var(--primary-300);
|
|
99
|
+
}
|
|
100
|
+
&[data-is-drag-accept="true"] {
|
|
101
|
+
border-color: var(--green-300);
|
|
102
|
+
}
|
|
103
|
+
&[data-is-drag-reject="true"] {
|
|
104
|
+
border-color: var(--red-300);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.smallSelectButton {
|
|
109
|
+
flex-shrink: 0;
|
|
110
|
+
& > * {
|
|
111
|
+
padding: 11px 8px;
|
|
27
112
|
}
|
|
28
113
|
}
|
|
29
114
|
|
|
@@ -70,12 +155,31 @@
|
|
|
70
155
|
}
|
|
71
156
|
}
|
|
72
157
|
|
|
158
|
+
.pedagoTabMenu {
|
|
159
|
+
align-self: stretch;
|
|
160
|
+
& > * {
|
|
161
|
+
background-color: transparent;
|
|
162
|
+
flex-wrap: wrap;
|
|
163
|
+
min-height: 100%;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.pedagoTab {
|
|
168
|
+
background-color: transparent;
|
|
169
|
+
padding: 4px 1.25rem;
|
|
170
|
+
gap: 16px;
|
|
171
|
+
font-weight: normal;
|
|
172
|
+
border-right: 1px solid var(--surface-300);
|
|
173
|
+
border-radius: 0;
|
|
174
|
+
:global(.p-highlight) & {
|
|
175
|
+
z-index: 1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
73
179
|
.pedagoContent {
|
|
180
|
+
flex-grow: 1;
|
|
74
181
|
overflow-y: auto;
|
|
75
|
-
:
|
|
76
|
-
grid-column-start: 1;
|
|
77
|
-
grid-row-start: 1;
|
|
78
|
-
}
|
|
182
|
+
text-align: center;
|
|
79
183
|
}
|
|
80
184
|
|
|
81
185
|
.pedagoFeedbackPanel {
|
package/src/index.css
CHANGED
|
@@ -33,11 +33,15 @@ body,
|
|
|
33
33
|
color-scheme: light;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
.
|
|
36
|
+
.editor-shell {
|
|
37
|
+
text-align: start;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.p-splitter-panel:has(> .meta-player-content-cover) {
|
|
37
41
|
position: relative;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
.meta-player-content-cover {
|
|
41
45
|
display: none;
|
|
42
46
|
width: 100%;
|
|
43
47
|
height: 100%;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { useCapytaleRichTextEditor } from "@capytale/capytale-rich-text-editor";
|
|
2
|
-
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
|
3
|
-
import {
|
|
4
|
-
selectAnswerSheetContent,
|
|
5
|
-
selectMode,
|
|
6
|
-
setCanSaveAnswerSheet,
|
|
7
|
-
setIsMPDirty,
|
|
8
|
-
setLexicalAnswerSheetState,
|
|
9
|
-
} from "../activityData/activityDataSlice";
|
|
10
|
-
import { forwardRef, useImperativeHandle, useRef } from "react";
|
|
11
|
-
import { Toast } from "primereact/toast";
|
|
12
|
-
import settings from "../../settings";
|
|
13
|
-
|
|
14
|
-
const AnswerSheetEditor: React.FC = forwardRef((_props, ref) => {
|
|
15
|
-
const [Editor, getState, _canSave] = useCapytaleRichTextEditor();
|
|
16
|
-
const dispatch = useAppDispatch();
|
|
17
|
-
const toast = useRef<Toast>(null);
|
|
18
|
-
const mode = useAppSelector(selectMode);
|
|
19
|
-
const isEditable =
|
|
20
|
-
mode === "create" || mode === "assignment" || mode === "review";
|
|
21
|
-
const initialEditorState = useAppSelector(selectAnswerSheetContent);
|
|
22
|
-
const initialStateOnChangeDone = useRef<boolean>(false);
|
|
23
|
-
|
|
24
|
-
useImperativeHandle(ref, () => {
|
|
25
|
-
return {
|
|
26
|
-
save: async () => {
|
|
27
|
-
const state = await getState();
|
|
28
|
-
dispatch(setLexicalAnswerSheetState(state.json));
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<>
|
|
35
|
-
<Toast position="bottom-right" ref={toast} />
|
|
36
|
-
<Editor
|
|
37
|
-
placeholderText="Écrivez le contenu initial de la fiche réponse ici..."
|
|
38
|
-
initialEditorState={initialEditorState}
|
|
39
|
-
jsonSizeLimit={settings.STATEMENT_MAX_SIZE}
|
|
40
|
-
onChange={(editorState) => {
|
|
41
|
-
dispatch(setLexicalAnswerSheetState(editorState));
|
|
42
|
-
if (initialStateOnChangeDone.current) {
|
|
43
|
-
dispatch(setIsMPDirty(true));
|
|
44
|
-
} else {
|
|
45
|
-
initialStateOnChangeDone.current = true;
|
|
46
|
-
}
|
|
47
|
-
}}
|
|
48
|
-
onJsonSizeLimitExceeded={() => {
|
|
49
|
-
dispatch(setCanSaveAnswerSheet(false));
|
|
50
|
-
toast.current!.show({
|
|
51
|
-
summary: "Erreur",
|
|
52
|
-
detail: `Le contenu de la fiche réponse est trop volumineux. Veuillez le réduire avant de l'enregistrer.\nPeut-être avez-vous inséré une image trop volumineuse ?`,
|
|
53
|
-
severity: "error",
|
|
54
|
-
life: 10000,
|
|
55
|
-
});
|
|
56
|
-
}}
|
|
57
|
-
onJsonSizeLimitMet={() => {
|
|
58
|
-
dispatch(setCanSaveAnswerSheet(true));
|
|
59
|
-
toast.current!.show({
|
|
60
|
-
summary: "Succès",
|
|
61
|
-
detail: `Le contenu de la fiche réponse ne dépasse plus la taille limite.`,
|
|
62
|
-
severity: "success",
|
|
63
|
-
life: 4000,
|
|
64
|
-
});
|
|
65
|
-
}}
|
|
66
|
-
isEditable={isEditable}
|
|
67
|
-
/>
|
|
68
|
-
</>
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
export default AnswerSheetEditor;
|