@local-civics/mgmt-ui 0.1.56 → 0.1.57

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/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { NotificationsProvider } from '@mantine/notifications';
2
2
  export { showNotification, updateNotification } from '@mantine/notifications';
3
- import { IconArrowLeft, IconCategory2, IconPlaylistAdd, IconChevronDown, IconClipboardCopy, IconCheck, IconTrash, IconDownload, IconX, IconCloudUpload, IconInfoCircle, IconColorSwatch, IconSwitchHorizontal, IconLogout, IconHome2, IconGauge, IconAlbum, IconLambda, IconBrandInstagram, IconBrandLinkedin, IconBrandFacebook } from '@tabler/icons';
3
+ import { IconChevronDown, IconClipboardCopy, IconTableExport, IconArrowLeft, IconCategory2, IconPlaylistAdd, IconCheck, IconTrash, IconDownload, IconX, IconCloudUpload, IconInfoCircle, IconColorSwatch, IconSwitchHorizontal, IconLogout, IconHome2, IconGauge, IconAlbum, IconLambda, IconBrandInstagram, IconBrandLinkedin, IconBrandFacebook } from '@tabler/icons';
4
4
  import * as React from 'react';
5
5
  import { useState } from 'react';
6
- import { createStyles, Text, Tabs as Tabs$1, Title, Image, Grid, Badge as Badge$1, ScrollArea, UnstyledButton, Group, Avatar, Table as Table$g, Container, Stack as Stack$3, ActionIcon, Button, LoadingOverlay, Select, Autocomplete, Menu, Drawer, Divider, TextInput, Tooltip, Paper, ThemeIcon, Card, Overlay, createEmotionCache, MantineProvider, Modal, Navbar as Navbar$1, Center, AppShell, Loader } from '@mantine/core';
6
+ import { createStyles, Text, Tabs as Tabs$1, Group, Button, Menu, ActionIcon, Title, Image, Grid, Badge as Badge$1, ScrollArea, UnstyledButton, Avatar, Table as Table$g, Container, Stack as Stack$3, LoadingOverlay, Select, Autocomplete, Drawer, Divider, TextInput, Tooltip, Paper, ThemeIcon, Card, Overlay, createEmotionCache, MantineProvider, Modal, Navbar as Navbar$1, Center, AppShell, Loader } from '@mantine/core';
7
7
  import { DataTable } from 'mantine-datatable';
8
8
  import { Dropzone, MIME_TYPES } from '@mantine/dropzone';
9
9
  import { useForm } from '@mantine/form';
@@ -11,7 +11,7 @@ import * as papa from 'papaparse';
11
11
  import { openConfirmModal, ModalsProvider } from '@mantine/modals';
12
12
  import { Chart } from 'react-charts';
13
13
 
14
- const useStyles$d = createStyles((theme) => ({
14
+ const useStyles$f = createStyles((theme) => ({
15
15
  root: {
16
16
  display: "flex",
17
17
  backgroundImage: `linear-gradient(-60deg, ${theme.colors[theme.primaryColor][4]} 0%, ${theme.colors[theme.primaryColor][7]} 100%)`,
@@ -58,7 +58,7 @@ const useStyles$d = createStyles((theme) => ({
58
58
  }
59
59
  }));
60
60
  const StatsGroup = ({ data }) => {
61
- const { classes } = useStyles$d();
61
+ const { classes } = useStyles$f();
62
62
  const stats = data.map((stat) => {
63
63
  const value = (() => {
64
64
  if (stat.unit === "%") {
@@ -77,7 +77,58 @@ const Tabs = (props) => {
77
77
  return /* @__PURE__ */ React.createElement(Tabs$1, { value: props.value, onTabChange: props.onChange }, /* @__PURE__ */ React.createElement(Tabs$1.List, null, tabs));
78
78
  };
79
79
 
80
- const useStyles$c = createStyles((theme) => ({
80
+ const useStyles$e = createStyles((theme) => ({
81
+ button: {
82
+ borderTopRightRadius: 0,
83
+ borderBottomRightRadius: 0,
84
+ marginLeft: 0,
85
+ marginRight: 0
86
+ },
87
+ menuControl: {
88
+ borderTopLeftRadius: 0,
89
+ borderBottomLeftRadius: 0,
90
+ border: 0,
91
+ borderLeft: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.white}`
92
+ }
93
+ }));
94
+ const SplitButton$2 = (props) => {
95
+ const { classes, theme } = useStyles$e();
96
+ const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
97
+ return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
98
+ Button,
99
+ {
100
+ className: classes.button,
101
+ variant: "gradient",
102
+ onClick: props.onPreviewClick
103
+ },
104
+ "Preview"
105
+ ), /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
106
+ ActionIcon,
107
+ {
108
+ variant: "gradient",
109
+ color: theme.primaryColor,
110
+ size: 36,
111
+ className: classes.menuControl
112
+ },
113
+ /* @__PURE__ */ React.createElement(IconChevronDown, { size: 16, stroke: 1.5 })
114
+ )), /* @__PURE__ */ React.createElement(Menu.Dropdown, null, /* @__PURE__ */ React.createElement(
115
+ Menu.Item,
116
+ {
117
+ icon: /* @__PURE__ */ React.createElement(IconClipboardCopy, { size: 16, stroke: 1.5, color: menuIconColor }),
118
+ onClick: props.onCopyLinkClick
119
+ },
120
+ "Copy link"
121
+ ), /* @__PURE__ */ React.createElement(
122
+ Menu.Item,
123
+ {
124
+ icon: /* @__PURE__ */ React.createElement(IconTableExport, { size: 16, stroke: 1.5, color: menuIconColor }),
125
+ onClick: props.onExportDataClick
126
+ },
127
+ "Export data (.csv)"
128
+ ))));
129
+ };
130
+
131
+ const useStyles$d = createStyles((theme) => ({
81
132
  wrapper: {
82
133
  display: "flex",
83
134
  alignItems: "center",
@@ -128,7 +179,7 @@ const useStyles$c = createStyles((theme) => ({
128
179
  }
129
180
  }));
130
181
  const PlaceholderBanner = (props) => {
131
- const { classes } = useStyles$c();
182
+ const { classes } = useStyles$d();
132
183
  const title = props.title || "Nothing to display";
133
184
  const description = props.description || "We don't have anything to show you here just yet. Add data, check back later, or adjust your search.";
134
185
  return /* @__PURE__ */ React.createElement("div", { className: classes.wrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.body }, /* @__PURE__ */ React.createElement(Title, { className: classes.title }, props.loading ? "Loading..." : title), /* @__PURE__ */ React.createElement(Text, { size: "sm", color: "dimmed" }, props.loading ? "Hold on, we're loading your data." : description)), /* @__PURE__ */ React.createElement(Image, { src: `https://cdn.localcivics.io/illustrations/${props.icon}.svg`, className: classes.image }));
@@ -138,7 +189,7 @@ function Stack$2(props) {
138
189
  if (props.items.length === 0) {
139
190
  return null;
140
191
  }
141
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, /* @__PURE__ */ React.createElement(Title, { color: "dark.4", size: "lg" }, row.lessonName)), /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, !!row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), !row.isComplete && !row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Not started"), !row.isComplete && !!row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "violet", variant: "filled" }, "In progress"))));
192
+ const rows = props.items.map((row) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, /* @__PURE__ */ React.createElement(Title, { color: "dark.4", size: "lg" }, row.lessonName)), /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, row.completion >= 1 && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), row.completion === 0 && !row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Not started"), row.completion > 0 && row.completion < 1 && /* @__PURE__ */ React.createElement(Badge$1, { color: "violet", variant: "filled" }, Math.round((row.completion + Number.EPSILON) * 100), "% Complete"))));
142
193
  return /* @__PURE__ */ React.createElement(Grid, { grow: true, gutter: "lg", sx: { padding: 20, minWidth: 700 } }, rows);
143
194
  }
144
195
 
@@ -200,7 +251,7 @@ function Table$e(props) {
200
251
  return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Lesson Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
201
252
  }
202
253
 
203
- const useStyles$b = createStyles((theme) => ({
254
+ const useStyles$c = createStyles((theme) => ({
204
255
  title: {
205
256
  fontSize: 34,
206
257
  fontWeight: 900,
@@ -213,7 +264,7 @@ const useStyles$b = createStyles((theme) => ({
213
264
  }
214
265
  }));
215
266
  const Badge = (props) => {
216
- const { classes } = useStyles$b();
267
+ const { classes } = useStyles$c();
217
268
  const [tab, setTab] = useState("lessons");
218
269
  const numberOfStudents = props.students.length;
219
270
  const percentageOfBadgesEarned = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length / numberOfStudents : 0;
@@ -226,12 +277,12 @@ const Badge = (props) => {
226
277
  },
227
278
  "Badges"
228
279
  ), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Badge"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Stack$3, { ml: "auto" }, /* @__PURE__ */ React.createElement(
229
- Button,
280
+ SplitButton$2,
230
281
  {
231
- variant: "gradient",
232
- onClick: props.onPreviewClick
233
- },
234
- "Preview"
282
+ onPreviewClick: props.onPreviewClick,
283
+ onCopyLinkClick: props.onCopyLinkClick,
284
+ onExportDataClick: props.onExportDataClick
285
+ }
235
286
  ))))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
236
287
  {
237
288
  title: "BADGE COMPLETION",
@@ -311,7 +362,7 @@ function Table$d(props) {
311
362
  return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { horizontalSpacing: 0, verticalSpacing: 0, sx: { minWidth: 700 } }, /* @__PURE__ */ React.createElement("tbody", null, rows)));
312
363
  }
313
364
 
314
- const useStyles$a = createStyles((theme) => ({
365
+ const useStyles$b = createStyles((theme) => ({
315
366
  title: {
316
367
  fontSize: 34,
317
368
  fontWeight: 900,
@@ -324,7 +375,7 @@ const useStyles$a = createStyles((theme) => ({
324
375
  }
325
376
  }));
326
377
  const Badges = (props) => {
327
- const { classes } = useStyles$a();
378
+ const { classes } = useStyles$b();
328
379
  return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled", size: "lg" }, "Badges"), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, "Badges and micro-credentials"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, "Project-sized skills acquisition and standards alignment."))), /* @__PURE__ */ React.createElement(
329
380
  Autocomplete,
330
381
  {
@@ -532,7 +583,7 @@ const Dashboard = (props) => {
532
583
  )))))));
533
584
  };
534
585
 
535
- const useStyles$9 = createStyles((theme) => ({
586
+ const useStyles$a = createStyles((theme) => ({
536
587
  button: {
537
588
  borderTopRightRadius: 0,
538
589
  borderBottomRightRadius: 0,
@@ -546,18 +597,19 @@ const useStyles$9 = createStyles((theme) => ({
546
597
  borderLeft: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.white}`
547
598
  }
548
599
  }));
549
- const SplitButton = (props) => {
550
- const { classes, theme } = useStyles$9();
600
+ const SplitButton$1 = (props) => {
601
+ const { classes, theme } = useStyles$a();
551
602
  const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
603
+ const hasMenu = !!props.withClassLink;
552
604
  return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
553
605
  Button,
554
606
  {
555
- className: classes.button,
607
+ className: hasMenu ? classes.button : "",
556
608
  leftIcon: /* @__PURE__ */ React.createElement(IconPlaylistAdd, { size: 14 }),
557
609
  onClick: props.onAddStudentsClick
558
610
  },
559
611
  "Add students"
560
- ), /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
612
+ ), hasMenu && /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
561
613
  ActionIcon,
562
614
  {
563
615
  variant: "filled",
@@ -566,7 +618,7 @@ const SplitButton = (props) => {
566
618
  className: classes.menuControl
567
619
  },
568
620
  /* @__PURE__ */ React.createElement(IconChevronDown, { size: 16, stroke: 1.5 })
569
- )), /* @__PURE__ */ React.createElement(Menu.Dropdown, null, /* @__PURE__ */ React.createElement(
621
+ )), /* @__PURE__ */ React.createElement(Menu.Dropdown, null, !!props.withClassLink && /* @__PURE__ */ React.createElement(
570
622
  Menu.Item,
571
623
  {
572
624
  icon: /* @__PURE__ */ React.createElement(IconClipboardCopy, { size: 16, stroke: 1.5, color: menuIconColor }),
@@ -619,7 +671,7 @@ var __spreadValues$3 = (a, b) => {
619
671
  return a;
620
672
  };
621
673
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
622
- const useStyles$8 = createStyles((theme) => ({
674
+ const useStyles$9 = createStyles((theme) => ({
623
675
  title: {
624
676
  fontSize: 34,
625
677
  fontWeight: 900,
@@ -649,7 +701,7 @@ const useStyles$8 = createStyles((theme) => ({
649
701
  }
650
702
  }));
651
703
  const Class = (props) => {
652
- const { classes } = useStyles$8();
704
+ const { classes } = useStyles$9();
653
705
  const form = useForm({
654
706
  initialValues: {
655
707
  classId: "",
@@ -713,8 +765,9 @@ const Class = (props) => {
713
765
  },
714
766
  "Classes"
715
767
  ), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Class"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Grid.Col, { sm: "content" }, !props.loading && /* @__PURE__ */ React.createElement(
716
- SplitButton,
768
+ SplitButton$1,
717
769
  {
770
+ withClassLink: props.withClassLink,
718
771
  onAddStudentsClick: () => setOpened(true),
719
772
  onCopyClassLinkClick: props.onCopyLinkClick
720
773
  }
@@ -729,14 +782,12 @@ const Class = (props) => {
729
782
  unit: "%"
730
783
  },
731
784
  {
732
- title: "BADGE COMPLETION",
733
- value: props.percentageOfBadgesEarned,
734
- unit: "%"
785
+ title: "BADGES EARNED",
786
+ value: props.numberOfBadgesEarned
735
787
  },
736
788
  {
737
- title: "LESSON COMPLETION",
738
- value: props.percentageOfLessonsCompleted,
739
- unit: "%"
789
+ title: "LESSONS COMPLETED",
790
+ value: props.numberOfLessonsCompleted
740
791
  }
741
792
  ] }), /* @__PURE__ */ React.createElement(
742
793
  Table$7,
@@ -749,7 +800,7 @@ const Class = (props) => {
749
800
  ))))));
750
801
  };
751
802
  const DropzoneButton = (props) => {
752
- const { classes, theme } = useStyles$8();
803
+ const { classes, theme } = useStyles$9();
753
804
  const openRef = React.useRef(null);
754
805
  const [loading, setLoading] = React.useState(false);
755
806
  const onDrop = React.useCallback((acceptedFiles) => {
@@ -835,7 +886,7 @@ var __spreadValues$2 = (a, b) => {
835
886
  }
836
887
  return a;
837
888
  };
838
- const useStyles$7 = createStyles((theme) => ({
889
+ const useStyles$8 = createStyles((theme) => ({
839
890
  title: {
840
891
  fontSize: 34,
841
892
  fontWeight: 900,
@@ -848,7 +899,7 @@ const useStyles$7 = createStyles((theme) => ({
848
899
  }
849
900
  }));
850
901
  const Classes = (props) => {
851
- const { classes } = useStyles$7();
902
+ const { classes } = useStyles$8();
852
903
  const form = useForm({
853
904
  initialValues: {
854
905
  classId: "",
@@ -911,7 +962,7 @@ const Classes = (props) => {
911
962
  ))))));
912
963
  };
913
964
 
914
- const useStyles$6 = createStyles((theme) => ({
965
+ const useStyles$7 = createStyles((theme) => ({
915
966
  title: {
916
967
  fontSize: 34,
917
968
  fontWeight: 900,
@@ -925,7 +976,7 @@ const useStyles$6 = createStyles((theme) => ({
925
976
  }
926
977
  }));
927
978
  const UserInfo = (props) => {
928
- const { classes } = useStyles$6();
979
+ const { classes } = useStyles$7();
929
980
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Title, { className: classes.title }, props.name), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "xs" }, props.impactStatement));
930
981
  };
931
982
 
@@ -1046,7 +1097,7 @@ const Student = (props) => {
1046
1097
  ))))));
1047
1098
  };
1048
1099
 
1049
- const useStyles$5 = createStyles((theme, props) => {
1100
+ const useStyles$6 = createStyles((theme, props) => {
1050
1101
  const from = props.from || "blue";
1051
1102
  const to = props.to || "green";
1052
1103
  return {
@@ -1074,7 +1125,7 @@ const useStyles$5 = createStyles((theme, props) => {
1074
1125
  };
1075
1126
  });
1076
1127
  function CardGradient(props) {
1077
- const { classes } = useStyles$5(props);
1128
+ const { classes } = useStyles$6(props);
1078
1129
  const from = props.from || "blue";
1079
1130
  const to = props.to || "green";
1080
1131
  const icon = props.icon || /* @__PURE__ */ React.createElement(IconColorSwatch, { size: 28, stroke: 1.5 });
@@ -1118,7 +1169,7 @@ var __objRest = (source, exclude) => {
1118
1169
  }
1119
1170
  return target;
1120
1171
  };
1121
- const useStyles$4 = createStyles((theme) => ({
1172
+ const useStyles$5 = createStyles((theme) => ({
1122
1173
  card: {
1123
1174
  height: 240,
1124
1175
  backgroundSize: "cover",
@@ -1163,7 +1214,7 @@ const TenantBanner = (_a) => {
1163
1214
  "style",
1164
1215
  "className"
1165
1216
  ]);
1166
- const { classes, cx, theme } = useStyles$4();
1217
+ const { classes, cx, theme } = useStyles$5();
1167
1218
  return /* @__PURE__ */ React.createElement(
1168
1219
  Card,
1169
1220
  __spreadValues$1({
@@ -1261,6 +1312,57 @@ function Table$2(props) {
1261
1312
  return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Rating"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1262
1313
  }
1263
1314
 
1315
+ const useStyles$4 = createStyles((theme) => ({
1316
+ button: {
1317
+ borderTopRightRadius: 0,
1318
+ borderBottomRightRadius: 0,
1319
+ marginLeft: 0,
1320
+ marginRight: 0
1321
+ },
1322
+ menuControl: {
1323
+ borderTopLeftRadius: 0,
1324
+ borderBottomLeftRadius: 0,
1325
+ border: 0,
1326
+ borderLeft: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.white}`
1327
+ }
1328
+ }));
1329
+ const SplitButton = (props) => {
1330
+ const { classes, theme } = useStyles$4();
1331
+ const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
1332
+ return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
1333
+ Button,
1334
+ {
1335
+ className: classes.button,
1336
+ variant: "gradient",
1337
+ onClick: props.onPreviewClick
1338
+ },
1339
+ "Preview"
1340
+ ), /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
1341
+ ActionIcon,
1342
+ {
1343
+ variant: "gradient",
1344
+ color: theme.primaryColor,
1345
+ size: 36,
1346
+ className: classes.menuControl
1347
+ },
1348
+ /* @__PURE__ */ React.createElement(IconChevronDown, { size: 16, stroke: 1.5 })
1349
+ )), /* @__PURE__ */ React.createElement(Menu.Dropdown, null, /* @__PURE__ */ React.createElement(
1350
+ Menu.Item,
1351
+ {
1352
+ icon: /* @__PURE__ */ React.createElement(IconClipboardCopy, { size: 16, stroke: 1.5, color: menuIconColor }),
1353
+ onClick: props.onCopyLinkClick
1354
+ },
1355
+ "Copy link"
1356
+ ), /* @__PURE__ */ React.createElement(
1357
+ Menu.Item,
1358
+ {
1359
+ icon: /* @__PURE__ */ React.createElement(IconTableExport, { size: 16, stroke: 1.5, color: menuIconColor }),
1360
+ onClick: props.onExportDataClick
1361
+ },
1362
+ "Export data (.csv)"
1363
+ ))));
1364
+ };
1365
+
1264
1366
  function Stack$1(props) {
1265
1367
  if (props.items.length === 0) {
1266
1368
  return null;
@@ -1402,12 +1504,12 @@ const Lesson = (props) => {
1402
1504
  },
1403
1505
  "Lessons"
1404
1506
  ), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Lesson"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Stack$3, { ml: "auto" }, /* @__PURE__ */ React.createElement(
1405
- Button,
1507
+ SplitButton,
1406
1508
  {
1407
- variant: "gradient",
1408
- onClick: props.onPreviewClick
1409
- },
1410
- "Preview"
1509
+ onPreviewClick: props.onPreviewClick,
1510
+ onCopyLinkClick: props.onCopyLinkClick,
1511
+ onExportDataClick: props.onExportDataClick
1512
+ }
1411
1513
  ))))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
1412
1514
  {
1413
1515
  title: "LESSON COMPLETION",