@capytale/meta-player 0.0.3 → 0.1.1
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 +1 -1
- package/src/App.tsx +12 -15
- package/src/MetaPlayer.tsx +1 -12
- package/src/app/store.ts +2 -0
- package/src/app.module.scss +1 -0
- package/src/demo.tsx +10 -8
- package/src/external/prime.ts +5 -0
- package/src/features/activityData/IsDirtySetter.tsx +0 -6
- package/src/features/activityData/MetaPlayerOptionsSetter.tsx +41 -0
- package/src/features/activityData/hooks.ts +9 -0
- package/src/features/activityJS/Saver.tsx +0 -1
- package/src/features/activitySettings/ActivitySettingsSetter.tsx +26 -0
- package/src/features/activitySettings/activitySettingsSlice.ts +43 -0
- package/src/features/activitySettings/hooks.ts +6 -0
- package/src/features/activitySettings/index.tsx +32 -0
- package/src/features/activitySettings/style.module.scss +4 -0
- package/src/features/activitySettings/types.ts +88 -0
- package/src/features/activitySettings/ui.tsx +393 -0
- package/src/features/navbar/ActivityMenu.tsx +30 -2
- package/src/features/navbar/CapytaleMenu.tsx +142 -124
- package/src/features/navbar/GradingNav.tsx +0 -1
- package/src/features/navbar/SidebarContent.tsx +38 -11
- package/src/features/navbar/style.module.scss +5 -14
- package/src/features/pedago/index.tsx +0 -2
- package/src/index.css +49 -0
- package/src/utils/equality.ts +32 -0
- package/src/features/activityData/OptionSetter.tsx +0 -35
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Button } from "primereact/button";
|
|
2
2
|
import { SplitButton } from "primereact/splitbutton";
|
|
3
3
|
import { ConfirmDialog, confirmDialog } from "primereact/confirmdialog";
|
|
4
|
+
import { Toast } from "primereact/toast";
|
|
4
5
|
|
|
5
6
|
import styles from "./style.module.scss";
|
|
6
|
-
import { useMemo } from "react";
|
|
7
|
+
import { useMemo, useRef } from "react";
|
|
7
8
|
import { useWindowSize } from "@uidotdev/usehooks";
|
|
8
9
|
import { ML, XL } from "../../utils/breakpoints";
|
|
9
10
|
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
|
@@ -38,6 +39,7 @@ const CapytaleMenu: React.FC = () => {
|
|
|
38
39
|
() => windowsSize.width && windowsSize.width < ML,
|
|
39
40
|
[windowsSize.width],
|
|
40
41
|
);
|
|
42
|
+
const toast = useRef<Toast>(null);
|
|
41
43
|
const changeWorkflow = (value: wf) => {
|
|
42
44
|
dispatch(setWorkflow(value));
|
|
43
45
|
dispatch(setSaveState("should-save"));
|
|
@@ -55,135 +57,151 @@ const CapytaleMenu: React.FC = () => {
|
|
|
55
57
|
});
|
|
56
58
|
};
|
|
57
59
|
return (
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
showOnDisabled: true,
|
|
72
|
-
}}
|
|
73
|
-
onClick={() => {
|
|
74
|
-
dispatch(setSaveState("should-save"));
|
|
75
|
-
}}
|
|
76
|
-
/>
|
|
77
|
-
)}
|
|
78
|
-
|
|
79
|
-
{mode === "create" && (
|
|
80
|
-
<SplitButton
|
|
81
|
-
label={isLarge ? sharingInfo.code : undefined}
|
|
82
|
-
severity="secondary"
|
|
83
|
-
size="small"
|
|
84
|
-
icon="pi pi-share-alt"
|
|
85
|
-
outlined
|
|
86
|
-
buttonProps={{
|
|
87
|
-
tooltip: "Copier le code de partage",
|
|
88
|
-
tooltipOptions: {
|
|
60
|
+
<>
|
|
61
|
+
<Toast ref={toast} position="bottom-right" />
|
|
62
|
+
<div className={styles.capytaleMenu}>
|
|
63
|
+
{showSaveButton && (
|
|
64
|
+
<Button
|
|
65
|
+
label={isQuiteSmall ? undefined : "Enregistrer"}
|
|
66
|
+
disabled={!isDirty}
|
|
67
|
+
severity={"warning"}
|
|
68
|
+
size="small"
|
|
69
|
+
icon="pi pi-save"
|
|
70
|
+
loading={saveState !== "idle"}
|
|
71
|
+
tooltip={isDirty ? "Enregistrer l'activité" : "Rien à enregistrer"}
|
|
72
|
+
tooltipOptions={{
|
|
89
73
|
position: "bottom",
|
|
90
74
|
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
75
|
+
showOnDisabled: true,
|
|
76
|
+
}}
|
|
77
|
+
onClick={() => {
|
|
78
|
+
dispatch(setSaveState("should-save"));
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
|
|
83
|
+
{mode === "create" && (
|
|
84
|
+
<SplitButton
|
|
85
|
+
label={isLarge ? sharingInfo.code : undefined}
|
|
86
|
+
severity="secondary"
|
|
87
|
+
size="small"
|
|
88
|
+
icon="pi pi-share-alt"
|
|
89
|
+
outlined
|
|
90
|
+
buttonProps={{
|
|
91
|
+
tooltip: "Copier le code de partage",
|
|
92
|
+
tooltipOptions: {
|
|
93
|
+
position: "bottom",
|
|
94
|
+
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
95
|
+
},
|
|
96
|
+
}}
|
|
97
|
+
onClick={async () => {
|
|
98
|
+
await copyToClipboard(sharingInfo.code);
|
|
99
|
+
toast.current!.show({
|
|
100
|
+
summary: "Code copié",
|
|
101
|
+
detail: "Le code de partage a été copié dans le presse-papier.",
|
|
102
|
+
severity: "info",
|
|
103
|
+
life: 2000,
|
|
104
|
+
});
|
|
105
|
+
}}
|
|
106
|
+
model={[
|
|
107
|
+
{
|
|
108
|
+
label: "Copier l'URL de partage",
|
|
109
|
+
icon: "pi pi-link",
|
|
110
|
+
command: () => {
|
|
111
|
+
copyToClipboard(sharingInfo.codeLink).then(() => {
|
|
112
|
+
toast.current!.show({
|
|
113
|
+
summary: "URL copiée",
|
|
114
|
+
detail:
|
|
115
|
+
"L'URL de partage a été copiée dans le presse-papier.",
|
|
116
|
+
severity: "info",
|
|
117
|
+
life: 2000,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
},
|
|
102
121
|
},
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
changeWorkflow("current");
|
|
122
|
+
]}
|
|
123
|
+
/>
|
|
124
|
+
)}
|
|
125
|
+
{mode === "assignment" && workflow === "current" && (
|
|
126
|
+
<Button
|
|
127
|
+
outlined
|
|
128
|
+
label="Rendre"
|
|
129
|
+
icon="pi pi-envelope"
|
|
130
|
+
onClick={() => {
|
|
131
|
+
confirmFinishAssignment();
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
)}
|
|
135
|
+
{mode === "assignment" && workflow !== "current" && (
|
|
136
|
+
<Button
|
|
137
|
+
outlined
|
|
138
|
+
label={workflow === "finished" ? "Rendue" : "Corrigée"}
|
|
139
|
+
disabled
|
|
140
|
+
icon={
|
|
141
|
+
workflow === "finished" ? "pi pi-envelope" : "pi pi-check-square"
|
|
142
|
+
}
|
|
143
|
+
tooltip="Copie déjà rendue"
|
|
144
|
+
/>
|
|
145
|
+
)}
|
|
146
|
+
{mode === "review" && (
|
|
147
|
+
<SplitButton
|
|
148
|
+
label={
|
|
149
|
+
workflow === "current"
|
|
150
|
+
? "En cours"
|
|
151
|
+
: workflow === "finished"
|
|
152
|
+
? "Rendue"
|
|
153
|
+
: "Corrigée"
|
|
154
|
+
}
|
|
155
|
+
severity="secondary"
|
|
156
|
+
size="small"
|
|
157
|
+
icon={
|
|
158
|
+
workflow === "current"
|
|
159
|
+
? "pi pi-pencil"
|
|
160
|
+
: workflow === "finished"
|
|
161
|
+
? "pi pi-envelope"
|
|
162
|
+
: "pi pi-check-square"
|
|
163
|
+
}
|
|
164
|
+
outlined
|
|
165
|
+
model={[
|
|
166
|
+
...(workflow === "current"
|
|
167
|
+
? []
|
|
168
|
+
: [
|
|
169
|
+
{
|
|
170
|
+
label: "Réautoriser la modification",
|
|
171
|
+
icon: "pi pi-pencil",
|
|
172
|
+
command: () => {
|
|
173
|
+
changeWorkflow("current");
|
|
174
|
+
},
|
|
157
175
|
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
176
|
+
]),
|
|
177
|
+
...(workflow === "finished"
|
|
178
|
+
? []
|
|
179
|
+
: [
|
|
180
|
+
{
|
|
181
|
+
label: "Marquer comme rendue",
|
|
182
|
+
icon: "pi pi-envelope",
|
|
183
|
+
command: () => {
|
|
184
|
+
changeWorkflow("finished");
|
|
185
|
+
},
|
|
168
186
|
},
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
187
|
+
]),
|
|
188
|
+
...(workflow === "corrected"
|
|
189
|
+
? []
|
|
190
|
+
: [
|
|
191
|
+
{
|
|
192
|
+
label: "Marquer comme corrigée",
|
|
193
|
+
icon: "pi pi-check-square",
|
|
194
|
+
command: () => {
|
|
195
|
+
changeWorkflow("corrected");
|
|
196
|
+
},
|
|
179
197
|
},
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
198
|
+
]),
|
|
199
|
+
]}
|
|
200
|
+
/>
|
|
201
|
+
)}
|
|
202
|
+
<ConfirmDialog />
|
|
203
|
+
</div>
|
|
204
|
+
</>
|
|
187
205
|
);
|
|
188
206
|
};
|
|
189
207
|
|
|
@@ -19,7 +19,6 @@ const GradingNav: React.FC = () => {
|
|
|
19
19
|
const nid = useAppSelector(selectNid) as number;
|
|
20
20
|
const mode = useAppSelector(selectMode);
|
|
21
21
|
const activityNid = useAppSelector(selectActivityNid) as number;
|
|
22
|
-
console.log("Le nid est : ", nid);
|
|
23
22
|
useEffect(() => {
|
|
24
23
|
evalApi.listSa(activityNid).then((j) => {
|
|
25
24
|
setStudentList(j);
|
|
@@ -19,8 +19,15 @@ import {
|
|
|
19
19
|
selectCanChoosePedagoLayout,
|
|
20
20
|
selectCanChooseTheme,
|
|
21
21
|
} from "../activityData/activityDataSlice";
|
|
22
|
+
import { ActivitySettingsDisplay } from "../activitySettings";
|
|
23
|
+
import { Button } from "primereact/button";
|
|
24
|
+
import settings from "../../settings";
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
type SidebarContentProps = {
|
|
27
|
+
showHelp?: () => void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const SidebarContent: FC<SidebarContentProps> = (props) => {
|
|
24
31
|
const canChooseOrientation = useAppSelector(selectCanChoosePedagoLayout);
|
|
25
32
|
const canChooseTheme = useAppSelector(selectCanChooseTheme);
|
|
26
33
|
const orientation = useAppSelector(selectOrientation);
|
|
@@ -29,11 +36,30 @@ const SidebarContent: FC = () => {
|
|
|
29
36
|
const dispatch = useAppDispatch();
|
|
30
37
|
return (
|
|
31
38
|
<>
|
|
39
|
+
{props.showHelp && (
|
|
40
|
+
<div className={styles.sidebarCapytaleActions}>
|
|
41
|
+
<Button
|
|
42
|
+
severity="secondary"
|
|
43
|
+
size="small"
|
|
44
|
+
icon={"pi pi-question-circle"}
|
|
45
|
+
onClick={() => {
|
|
46
|
+
props.showHelp!();
|
|
47
|
+
}}
|
|
48
|
+
outlined
|
|
49
|
+
label="Documentation"
|
|
50
|
+
tooltip="Voir la documentation"
|
|
51
|
+
tooltipOptions={{
|
|
52
|
+
position: "left",
|
|
53
|
+
showDelay: settings.TOOLTIP_SHOW_DELAY,
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
)}
|
|
32
58
|
{sidebarActions.length > 0 && (
|
|
33
59
|
<Fieldset
|
|
34
60
|
legend="Actions"
|
|
35
61
|
className={classNames(
|
|
36
|
-
|
|
62
|
+
"sidebarFieldset",
|
|
37
63
|
styles.sidebarFieldsetButtons,
|
|
38
64
|
)}
|
|
39
65
|
>
|
|
@@ -41,9 +67,9 @@ const SidebarContent: FC = () => {
|
|
|
41
67
|
</Fieldset>
|
|
42
68
|
)}
|
|
43
69
|
{canChooseOrientation && (
|
|
44
|
-
<Fieldset legend="Disposition" className=
|
|
45
|
-
<div className=
|
|
46
|
-
<div className=
|
|
70
|
+
<Fieldset legend="Disposition" className="sidebarFieldset">
|
|
71
|
+
<div className="sidebarRadioButtons">
|
|
72
|
+
<div className="sidebarRadioGroup">
|
|
47
73
|
<RadioButton
|
|
48
74
|
inputId="rb-horizontal"
|
|
49
75
|
name="horizontal"
|
|
@@ -55,7 +81,7 @@ const SidebarContent: FC = () => {
|
|
|
55
81
|
Horizontale
|
|
56
82
|
</label>
|
|
57
83
|
</div>
|
|
58
|
-
<div className=
|
|
84
|
+
<div className="sidebarRadioGroup">
|
|
59
85
|
<RadioButton
|
|
60
86
|
inputId="rb-vertical"
|
|
61
87
|
name="vertical"
|
|
@@ -71,9 +97,9 @@ const SidebarContent: FC = () => {
|
|
|
71
97
|
</Fieldset>
|
|
72
98
|
)}
|
|
73
99
|
{canChooseTheme && (
|
|
74
|
-
<Fieldset legend="Thème" className=
|
|
75
|
-
<div className=
|
|
76
|
-
<div className=
|
|
100
|
+
<Fieldset legend="Thème" className="sidebarFieldset">
|
|
101
|
+
<div className="sidebarRadioButtons">
|
|
102
|
+
<div className="sidebarRadioGroup">
|
|
77
103
|
<RadioButton
|
|
78
104
|
inputId="rb-light"
|
|
79
105
|
name="light"
|
|
@@ -88,7 +114,7 @@ const SidebarContent: FC = () => {
|
|
|
88
114
|
Clair
|
|
89
115
|
</label>
|
|
90
116
|
</div>
|
|
91
|
-
<div className=
|
|
117
|
+
<div className="sidebarRadioGroup">
|
|
92
118
|
<RadioButton
|
|
93
119
|
inputId="rb-dark"
|
|
94
120
|
name="dark"
|
|
@@ -103,7 +129,7 @@ const SidebarContent: FC = () => {
|
|
|
103
129
|
Sombre
|
|
104
130
|
</label>
|
|
105
131
|
</div>
|
|
106
|
-
<div className=
|
|
132
|
+
<div className="sidebarRadioGroup">
|
|
107
133
|
<RadioButton
|
|
108
134
|
inputId="rb-auto"
|
|
109
135
|
name="auto"
|
|
@@ -118,6 +144,7 @@ const SidebarContent: FC = () => {
|
|
|
118
144
|
</div>
|
|
119
145
|
</Fieldset>
|
|
120
146
|
)}
|
|
147
|
+
<ActivitySettingsDisplay />
|
|
121
148
|
</>
|
|
122
149
|
);
|
|
123
150
|
};
|
|
@@ -139,24 +139,15 @@
|
|
|
139
139
|
align-items: center;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
.sidebarFieldset {
|
|
143
|
-
margin-bottom: 8px;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
142
|
.sidebarFieldsetButtons :global(.p-fieldset-content) {
|
|
147
143
|
display: flex;
|
|
148
144
|
flex-direction: column;
|
|
149
145
|
gap: 6px;
|
|
150
146
|
}
|
|
151
147
|
|
|
152
|
-
.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.sidebarRadioGroup {
|
|
159
|
-
display: flex;
|
|
160
|
-
gap: 8px;
|
|
161
|
-
align-items: center;
|
|
148
|
+
.sidebarCapytaleActions {
|
|
149
|
+
margin-bottom: 8px;
|
|
150
|
+
& > button {
|
|
151
|
+
width: 100%;
|
|
152
|
+
}
|
|
162
153
|
}
|
|
@@ -48,7 +48,6 @@ const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
|
48
48
|
) => {
|
|
49
49
|
dispatch(setComments(event.target.value));
|
|
50
50
|
dispatch(setIsMPDirty(true));
|
|
51
|
-
console.log("51");
|
|
52
51
|
};
|
|
53
52
|
|
|
54
53
|
const handleGradingChange: ChangeEventHandler<HTMLTextAreaElement> = (
|
|
@@ -56,7 +55,6 @@ const Pedago: React.FC<DivProps> = ({ className, ...props }) => {
|
|
|
56
55
|
) => {
|
|
57
56
|
dispatch(setGrading(event.target.value));
|
|
58
57
|
dispatch(setIsMPDirty(true));
|
|
59
|
-
console.log("59");
|
|
60
58
|
};
|
|
61
59
|
|
|
62
60
|
return (
|
package/src/index.css
CHANGED
|
@@ -33,8 +33,57 @@ body,
|
|
|
33
33
|
color-scheme: light;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
.p-splitter-panel:has(> #meta-player-content-cover) {
|
|
37
|
+
position: relative;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#meta-player-content-cover {
|
|
41
|
+
display: none;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
position: absolute;
|
|
45
|
+
top: 0;
|
|
46
|
+
left: 0;
|
|
47
|
+
z-index: 1000;
|
|
48
|
+
background-color: rgba(0, 0, 0, 0);
|
|
49
|
+
.p-splitter-resizing & {
|
|
50
|
+
display: block;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
36
54
|
#meta-player-content,
|
|
37
55
|
:has(> #meta-player-content) {
|
|
38
56
|
height: 100%;
|
|
39
57
|
background-color: var(--surface-a);
|
|
40
58
|
}
|
|
59
|
+
|
|
60
|
+
.sidebarFieldset {
|
|
61
|
+
margin-bottom: 8px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.sidebarRadioButtons {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: 4px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.sidebarRadioGroup {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: 8px;
|
|
73
|
+
align-items: center;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#metaPlayerHelpDialog {
|
|
77
|
+
width: 80vw;
|
|
78
|
+
height: 80vh;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#metaPlayerHelpDialog_content {
|
|
82
|
+
padding: 0;
|
|
83
|
+
& iframe {
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
border: 0;
|
|
87
|
+
display: block;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// https://medium.com/@stheodorejohn/javascript-object-deep-equality-comparison-in-javascript-7aa227e889d4
|
|
2
|
+
|
|
3
|
+
export function deepEqual(obj1: any, obj2: any): boolean {
|
|
4
|
+
// Base case: If both objects are identical, return true.
|
|
5
|
+
if (obj1 === obj2) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
// Check if both objects are objects and not null.
|
|
9
|
+
if (
|
|
10
|
+
typeof obj1 !== "object" ||
|
|
11
|
+
typeof obj2 !== "object" ||
|
|
12
|
+
obj1 === null ||
|
|
13
|
+
obj2 === null
|
|
14
|
+
) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
// Get the keys of both objects.
|
|
18
|
+
const keys1 = Object.keys(obj1);
|
|
19
|
+
const keys2 = Object.keys(obj2);
|
|
20
|
+
// Check if the number of keys is the same.
|
|
21
|
+
if (keys1.length !== keys2.length) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
// Iterate through the keys and compare their values recursively.
|
|
25
|
+
for (const key of keys1) {
|
|
26
|
+
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// If all checks pass, the objects are deep equal.
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
2
|
-
import { useAppDispatch } from "../../app/hooks";
|
|
3
|
-
import { setPlayerSettings } from "./activityDataSlice";
|
|
4
|
-
import { setLayout } from "../layout/layoutSlice";
|
|
5
|
-
import { setAutoSwitch, switchToTheme } from "../theming/themingSlice";
|
|
6
|
-
import { MetaPlayerOptions } from "./metaPlayerOptions";
|
|
7
|
-
|
|
8
|
-
type OptionSetterProps = {
|
|
9
|
-
options: MetaPlayerOptions;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const OptionSetter: FC<OptionSetterProps> = ({ options }) => {
|
|
13
|
-
const dispatch = useAppDispatch();
|
|
14
|
-
if (!options.supportsLightTheme && !options.supportsDarkTheme) {
|
|
15
|
-
throw new Error("At least one theme must be supported");
|
|
16
|
-
}
|
|
17
|
-
dispatch(setPlayerSettings(options));
|
|
18
|
-
dispatch(
|
|
19
|
-
setLayout(
|
|
20
|
-
options.pedagoLayout === "horizontal" ||
|
|
21
|
-
options.pedagoLayout === "default-horizontal"
|
|
22
|
-
? "horizontal"
|
|
23
|
-
: "vertical",
|
|
24
|
-
),
|
|
25
|
-
);
|
|
26
|
-
if (options.supportsDarkTheme && options.supportsLightTheme) {
|
|
27
|
-
dispatch(setAutoSwitch(true));
|
|
28
|
-
} else {
|
|
29
|
-
dispatch(setAutoSwitch(false));
|
|
30
|
-
dispatch(switchToTheme(options.supportsLightTheme ? "light" : "dark"));
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default OptionSetter;
|