@vue-skuilder/common-ui 0.2.34 → 0.2.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs +13 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPrimitive.mjs +15 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPropertyKey.mjs +10 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/typeof.mjs +12 -0
  5. package/dist/_virtual/_plugin-vue_export-helper.mjs +9 -0
  6. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  7. package/dist/admin/admin.css +1 -1
  8. package/dist/admin/common-ui-admin.es.js +1074 -473
  9. package/dist/admin/common-ui-admin.es.js.map +1 -1
  10. package/dist/admin/components/EChart.vue.d.ts +14 -0
  11. package/dist/admin/components/EChart.vue.d.ts.map +1 -0
  12. package/dist/admin/components/LearnerDiagnostics.vue.d.ts +3 -3
  13. package/dist/admin/components/LearnerDiagnostics.vue.d.ts.map +1 -1
  14. package/dist/admin/components/LearnerTagElo.vue.d.ts +14 -0
  15. package/dist/admin/components/LearnerTagElo.vue.d.ts.map +1 -0
  16. package/dist/admin/index.d.ts +1 -0
  17. package/dist/admin/index.d.ts.map +1 -1
  18. package/dist/assets/index.css +2 -1
  19. package/dist/components/CardBrowser.mjs +63 -0
  20. package/dist/components/CardBrowser.mjs.map +1 -0
  21. package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs +50 -0
  22. package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
  23. package/dist/components/CardHistoryViewer.mjs +70 -0
  24. package/dist/components/CardHistoryViewer.mjs.map +1 -0
  25. package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs +108 -0
  26. package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs.map +1 -0
  27. package/dist/components/CardSearch.mjs +26 -0
  28. package/dist/components/CardSearch.mjs.map +1 -0
  29. package/dist/components/CardSearch.vue_vue_type_script_lang.mjs +17 -0
  30. package/dist/components/CardSearch.vue_vue_type_script_lang.mjs.map +1 -0
  31. package/dist/components/CardSearchResults.mjs +32 -0
  32. package/dist/components/CardSearchResults.mjs.map +1 -0
  33. package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs +71 -0
  34. package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs.map +1 -0
  35. package/dist/components/CourseCardBrowser.mjs +175 -0
  36. package/dist/components/CourseCardBrowser.mjs.map +1 -0
  37. package/dist/components/CourseCardBrowser.vue.d.ts +3 -3
  38. package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs +173 -0
  39. package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
  40. package/dist/components/CourseInformation.mjs +132 -0
  41. package/dist/components/CourseInformation.mjs.map +1 -0
  42. package/dist/components/CourseInformation.vue.d.ts +3 -3
  43. package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs +56 -0
  44. package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs.map +1 -0
  45. package/dist/components/CourseTagFilterWidget.mjs +114 -0
  46. package/dist/components/CourseTagFilterWidget.mjs.map +1 -0
  47. package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs +65 -0
  48. package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs.map +1 -0
  49. package/dist/components/HeatMap.mjs +40 -0
  50. package/dist/components/HeatMap.mjs.map +1 -0
  51. package/dist/components/HeatMap.vue_vue_type_script_lang.mjs +211 -0
  52. package/dist/components/HeatMap.vue_vue_type_script_lang.mjs.map +1 -0
  53. package/dist/components/PaginatingToolbar.mjs +94 -0
  54. package/dist/components/PaginatingToolbar.mjs.map +1 -0
  55. package/dist/components/PaginatingToolbar.vue.d.ts +3 -3
  56. package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs +36 -0
  57. package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs.map +1 -0
  58. package/dist/components/SessionControllerDebug.mjs +130 -0
  59. package/dist/components/SessionControllerDebug.mjs.map +1 -0
  60. package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs +45 -0
  61. package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs.map +1 -0
  62. package/dist/components/SkMouseTrap.mjs +66 -0
  63. package/dist/components/SkMouseTrap.mjs.map +1 -0
  64. package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs +31 -0
  65. package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs.map +1 -0
  66. package/dist/components/SkMouseTrapToolTip.mjs +28 -0
  67. package/dist/components/SkMouseTrapToolTip.mjs.map +1 -0
  68. package/dist/components/SkMouseTrapToolTip.vue.d.ts +1 -1
  69. package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs +91 -0
  70. package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs.map +1 -0
  71. package/dist/components/SnackbarService.mjs +24 -0
  72. package/dist/components/SnackbarService.mjs.map +1 -0
  73. package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs +34 -0
  74. package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs.map +1 -0
  75. package/dist/components/SnackbarService2.mjs +40 -0
  76. package/dist/components/SnackbarService2.mjs.map +1 -0
  77. package/dist/components/StudySession.mjs +123 -0
  78. package/dist/components/StudySession.mjs.map +1 -0
  79. package/dist/components/StudySession.vue_vue_type_script_lang.mjs +280 -0
  80. package/dist/components/StudySession.vue_vue_type_script_lang.mjs.map +1 -0
  81. package/dist/components/StudySessionTimer.mjs +50 -0
  82. package/dist/components/StudySessionTimer.mjs.map +1 -0
  83. package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs +43 -0
  84. package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs.map +1 -0
  85. package/dist/components/TagsInput.mjs +45 -0
  86. package/dist/components/TagsInput.mjs.map +1 -0
  87. package/dist/components/TagsInput.vue_vue_type_script_lang.mjs +117 -0
  88. package/dist/components/TagsInput.vue_vue_type_script_lang.mjs.map +1 -0
  89. package/dist/components/UserTagPreferences.mjs +205 -0
  90. package/dist/components/UserTagPreferences.mjs.map +1 -0
  91. package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs +139 -0
  92. package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs.map +1 -0
  93. package/dist/components/auth/RequestPasswordReset.mjs +96 -0
  94. package/dist/components/auth/RequestPasswordReset.mjs.map +1 -0
  95. package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs +47 -0
  96. package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs.map +1 -0
  97. package/dist/components/auth/ResetPassword.mjs +129 -0
  98. package/dist/components/auth/ResetPassword.mjs.map +1 -0
  99. package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs +69 -0
  100. package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs.map +1 -0
  101. package/dist/components/auth/UserChip.mjs +9 -0
  102. package/dist/components/auth/UserChip.mjs.map +1 -0
  103. package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs +213 -0
  104. package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  105. package/dist/components/auth/UserLogin.mjs +9 -0
  106. package/dist/components/auth/UserLogin.mjs.map +1 -0
  107. package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs +155 -0
  108. package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  109. package/dist/components/auth/UserLoginAndRegistrationContainer.mjs +9 -0
  110. package/dist/components/auth/UserLoginAndRegistrationContainer.mjs.map +1 -0
  111. package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs +126 -0
  112. package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  113. package/dist/components/auth/UserRegistration.mjs +147 -0
  114. package/dist/components/auth/UserRegistration.mjs.map +1 -0
  115. package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs +130 -0
  116. package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs.map +1 -0
  117. package/dist/components/auth/VerifyEmail.mjs +118 -0
  118. package/dist/components/auth/VerifyEmail.mjs.map +1 -0
  119. package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs +59 -0
  120. package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs.map +1 -0
  121. package/dist/components/cardRendering/AudioAutoPlayer.mjs +9 -0
  122. package/dist/components/cardRendering/AudioAutoPlayer.mjs.map +1 -0
  123. package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs +69 -0
  124. package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  125. package/dist/components/cardRendering/CardLoader.mjs +31 -0
  126. package/dist/components/cardRendering/CardLoader.mjs.map +1 -0
  127. package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs +75 -0
  128. package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs.map +1 -0
  129. package/dist/components/cardRendering/CardViewer.mjs +39 -0
  130. package/dist/components/cardRendering/CardViewer.mjs.map +1 -0
  131. package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs +66 -0
  132. package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs.map +1 -0
  133. package/dist/components/cardRendering/CodeBlockRenderer.mjs +8 -0
  134. package/dist/components/cardRendering/CodeBlockRenderer.mjs.map +1 -0
  135. package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs +44 -0
  136. package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  137. package/dist/components/cardRendering/MarkdownRenderer.mjs +21 -0
  138. package/dist/components/cardRendering/MarkdownRenderer.mjs.map +1 -0
  139. package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs +24 -0
  140. package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs.map +1 -0
  141. package/dist/components/cardRendering/MarkdownRendererHelpers.mjs +79 -0
  142. package/dist/components/cardRendering/MarkdownRendererHelpers.mjs.map +1 -0
  143. package/dist/components/cardRendering/MdTokenRenderer.mjs +9 -0
  144. package/dist/components/cardRendering/MdTokenRenderer.mjs.map +1 -0
  145. package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs +176 -0
  146. package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  147. package/dist/components/studentInputs/BaseUserInput.mjs +54 -0
  148. package/dist/components/studentInputs/BaseUserInput.mjs.map +1 -0
  149. package/dist/components/studentInputs/MultipleChoiceOption.mjs +26 -0
  150. package/dist/components/studentInputs/MultipleChoiceOption.mjs.map +1 -0
  151. package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs +76 -0
  152. package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs.map +1 -0
  153. package/dist/components/studentInputs/RadioMultipleChoice.mjs +33 -0
  154. package/dist/components/studentInputs/RadioMultipleChoice.mjs.map +1 -0
  155. package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs +105 -0
  156. package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs.map +1 -0
  157. package/dist/components/studentInputs/TrueFalse.mjs +19 -0
  158. package/dist/components/studentInputs/TrueFalse.mjs.map +1 -0
  159. package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs +21 -0
  160. package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs.map +1 -0
  161. package/dist/components/studentInputs/UserInputNumber.mjs +33 -0
  162. package/dist/components/studentInputs/UserInputNumber.mjs.map +1 -0
  163. package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs +25 -0
  164. package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs.map +1 -0
  165. package/dist/components/studentInputs/UserInputString.mjs +22 -0
  166. package/dist/components/studentInputs/UserInputString.mjs.map +1 -0
  167. package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs +23 -0
  168. package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs.map +1 -0
  169. package/dist/components/studentInputs/fillInInput.mjs +25 -0
  170. package/dist/components/studentInputs/fillInInput.mjs.map +1 -0
  171. package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs +26 -0
  172. package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs.map +1 -0
  173. package/dist/composables/CompositionViewable.mjs +65 -0
  174. package/dist/composables/CompositionViewable.mjs.map +1 -0
  175. package/dist/composables/Displayable.mjs +36 -0
  176. package/dist/composables/Displayable.mjs.map +1 -0
  177. package/dist/composables/useAuthUI.mjs +38 -0
  178. package/dist/composables/useAuthUI.mjs.map +1 -0
  179. package/dist/composables/useEntitlements.mjs +58 -0
  180. package/dist/composables/useEntitlements.mjs.map +1 -0
  181. package/dist/index.mjs +49 -0
  182. package/dist/plugins/pinia.mjs +12 -0
  183. package/dist/plugins/pinia.mjs.map +1 -0
  184. package/dist/services/authAPI.mjs +159 -0
  185. package/dist/services/authAPI.mjs.map +1 -0
  186. package/dist/stores/useAuthStore.mjs +68 -0
  187. package/dist/stores/useAuthStore.mjs.map +1 -0
  188. package/dist/stores/useCardPreviewModeStore.mjs +20 -0
  189. package/dist/stores/useCardPreviewModeStore.mjs.map +1 -0
  190. package/dist/stores/useConfigStore.mjs +60 -0
  191. package/dist/stores/useConfigStore.mjs.map +1 -0
  192. package/dist/utils/SkldrMouseTrap.mjs +48 -0
  193. package/dist/utils/SkldrMouseTrap.mjs.map +1 -0
  194. package/dist/utils/passwordValidation.mjs +12 -0
  195. package/dist/utils/passwordValidation.mjs.map +1 -0
  196. package/package.json +8 -8
  197. package/src/admin/components/EChart.vue +59 -0
  198. package/src/admin/components/LearnerDiagnostics.vue +8 -4
  199. package/src/admin/components/LearnerTagElo.vue +563 -0
  200. package/src/admin/index.ts +1 -0
  201. package/dist/MarkdownRenderer-U_iPiA2x.mjs +0 -4966
  202. package/dist/MarkdownRenderer-U_iPiA2x.mjs.map +0 -1
  203. package/dist/assets/MarkdownRenderer.css +0 -1
  204. package/dist/common-ui.es.js +0 -5090
  205. package/dist/common-ui.es.js.map +0 -1
  206. package/dist/common-ui.umd.js +0 -77
  207. package/dist/common-ui.umd.js.map +0 -1
@@ -0,0 +1,130 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import { alertUser as e } from "../SnackbarService.mjs";
3
+ import { sendVerificationEmail as t } from "../../services/authAPI.mjs";
4
+ import { getCurrentUser as n, useAuthStore as r } from "../../stores/useAuthStore.mjs";
5
+ import { validatePassword as i } from "../../utils/passwordValidation.mjs";
6
+ import { defineComponent as a } from "vue";
7
+ import { Status as o, log as s } from "@vue-skuilder/common";
8
+ //#region src/components/auth/UserRegistration.vue?vue&type=script&lang.ts
9
+ var c = a({
10
+ name: "UserRegistration",
11
+ props: { onSignupSuccess: {
12
+ type: Function,
13
+ required: !1
14
+ } },
15
+ emits: ["toggle", "signup-success"],
16
+ data() {
17
+ return {
18
+ email: "",
19
+ username: "",
20
+ password: "",
21
+ retypedPassword: "",
22
+ passwordVisible: !1,
23
+ emailError: !1,
24
+ emailHint: "",
25
+ usernameValidationInProgress: !1,
26
+ usernameError: !1,
27
+ usernameHint: "",
28
+ awaitingResponse: !1,
29
+ badLoginAttempt: !1,
30
+ userSecret: "",
31
+ secret: "goons",
32
+ user: null,
33
+ roles: [
34
+ "Student",
35
+ "Teacher",
36
+ "Author"
37
+ ],
38
+ student: !0,
39
+ teacher: !1,
40
+ author: !1,
41
+ authStore: r()
42
+ };
43
+ },
44
+ computed: {
45
+ registrationRoute() {
46
+ return typeof this.$route.name == "string" && this.$route.name.toLowerCase() === "signup";
47
+ },
48
+ buttonStatus() {
49
+ return {
50
+ color: this.badLoginAttempt ? "error" : "success",
51
+ text: this.badLoginAttempt ? "Try again" : "Log In"
52
+ };
53
+ },
54
+ passwordError() {
55
+ return i(this.password);
56
+ },
57
+ passwordRetypeError() {
58
+ return console.log("[RTE]"), this.password === this.retypedPassword ? "" : "Passwords must match.";
59
+ }
60
+ },
61
+ async created() {
62
+ this.user = await n();
63
+ },
64
+ methods: {
65
+ toggle() {
66
+ s("Toggling registration / login forms."), this.$emit("toggle");
67
+ },
68
+ validateEmail() {
69
+ this.emailError = !1, this.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email) ? (this.emailError = !0, this.emailHint = "Please enter a valid email address") : this.emailHint = "";
70
+ },
71
+ validateUsername() {
72
+ this.usernameError = !1;
73
+ },
74
+ async createUser() {
75
+ if (this.awaitingResponse = !0, this.passwordError) {
76
+ e({
77
+ text: this.passwordError,
78
+ status: o.error
79
+ }), this.awaitingResponse = !1;
80
+ return;
81
+ }
82
+ if (s(`
83
+ User creation
84
+ -------------
85
+
86
+ Name: ${this.username}
87
+ Student: ${this.student}
88
+ Teacher: ${this.teacher}
89
+ Author: ${this.author}
90
+ `), this.password === this.retypedPassword) {
91
+ if (!this.user) {
92
+ console.error("ERROR: No user object available");
93
+ return;
94
+ }
95
+ this.user.createAccount(this.username, this.password).then(async (n) => {
96
+ if (n.status === o.ok) {
97
+ if (this.authStore.loginAndRegistration.loggedIn = !0, this.authStore.loginAndRegistration.init = !1, this.authStore.loginAndRegistration.init = !0, this.email) try {
98
+ let n = typeof window < "u" ? window.location.origin : void 0, r = await t(this.username, this.email, n);
99
+ r.ok ? e({
100
+ text: "Account created! Please check your email to verify your account.",
101
+ status: o.ok
102
+ }) : s(`Warning: Failed to send verification email: ${r.error}`);
103
+ } catch (e) {
104
+ console.error("Email save/send error:", e), s(`Warning: Failed to save email or send verification: ${e}`);
105
+ }
106
+ this.onSignupSuccess && (console.log("[UserRegistration] Calling onSignupSuccess callback"), this.onSignupSuccess({ username: this.username })), this.$emit("signup-success", { username: this.username });
107
+ } else n.error === "This username is taken!" ? (this.usernameError = !0, this.usernameHint = "Try a different name.", this.$refs.userNameTextField.focus(), e({
108
+ text: `The name ${this.username} is taken!`,
109
+ status: n.status
110
+ })) : e({
111
+ text: n.error,
112
+ status: n.status
113
+ });
114
+ }).catch((t) => {
115
+ console.error("[UserRegistration] .catch() called with error:", t), t && e({
116
+ text: t?.message || t?.error || t?.toString() || "Account creation failed",
117
+ status: o.error
118
+ });
119
+ }), this.awaitingResponse = !1;
120
+ } else e({
121
+ text: "Passwords do not match.",
122
+ status: o.error
123
+ }), this.awaitingResponse = !1;
124
+ }
125
+ }
126
+ });
127
+ //#endregion
128
+ export { c as default };
129
+
130
+ //# sourceMappingURL=UserRegistration.vue_vue_type_script_lang.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserRegistration.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/auth/UserRegistration.vue"],"sourcesContent":["<template>\n <v-card>\n <v-card-title class=\"text-h5 bg-grey-lighten-2\"> Create an Account </v-card-title>\n\n <v-card-text>\n <v-form @submit.prevent=\"createUser\">\n <v-text-field\n v-model=\"email\"\n name=\"email\"\n label=\"Email address\"\n type=\"email\"\n prepend-icon=\"mdi-email\"\n :error=\"emailError\"\n :hint=\"emailHint\"\n @blur=\"validateEmail\"\n ></v-text-field>\n <v-text-field\n id=\"\"\n ref=\"userNameTextField\"\n v-model=\"username\"\n name=\"username\"\n label=\"Choose a Username\"\n prepend-icon=\"mdi-account-circle\"\n :error=\"usernameError\"\n :hint=\"usernameHint\"\n @blur=\"validateUsername\"\n ></v-text-field>\n <v-text-field\n v-model=\"password\"\n prepend-icon=\"mdi-lock\"\n name=\"password\"\n hover=\"Show password\"\n label=\"Create a password\"\n :hint=\"passwordError\"\n :error=\"!!passwordError\"\n min=\"4\"\n :append-icon=\"passwordVisible ? 'mdi-eye-off' : 'mdi-eye'\"\n :type=\"passwordVisible ? 'text' : 'password'\"\n @click:append=\"() => (passwordVisible = !passwordVisible)\"\n ></v-text-field>\n <v-text-field\n v-model=\"retypedPassword\"\n prepend-icon=\"mdi-lock\"\n name=\"retypedPassword\"\n hover=\"Show password\"\n label=\"Retype your password\"\n :disabled=\"password === '' || !!passwordError\"\n :hint=\"passwordRetypeError\"\n min=\"4\"\n :type=\"passwordVisible ? 'text' : 'password'\"\n ></v-text-field>\n\n <!-- <v-checkbox label=\"Student\" v-model=\"student\" ></v-checkbox>\n <v-checkbox label=\"Teacher\" v-model=\"teacher\" ></v-checkbox>\n <v-checkbox label=\"Author\" v-model=\"author\" ></v-checkbox> -->\n\n <v-snackbar v-model=\"badLoginAttempt\" location=\"bottom right\" :timeout=\"5000\">\n Username or password was incorrect.\n <v-btn color=\"pink\" variant=\"text\" @click=\"badLoginAttempt = false\"> Close </v-btn>\n </v-snackbar>\n <v-btn\n class=\"mr-2 my-2\"\n type=\"submit\"\n :loading=\"awaitingResponse\"\n :color=\"buttonStatus.color\"\n :disabled=\"!!passwordError || password !== retypedPassword\"\n >\n <v-icon start>mdi-lock-open</v-icon>\n Create Account\n </v-btn>\n <router-link v-if=\"registrationRoute\" to=\"login\">\n <v-btn variant=\"text\">Log In</v-btn>\n </router-link>\n <v-btn v-else variant=\"text\" @click=\"toggle\"> Log In </v-btn>\n </v-form>\n </v-card-text>\n </v-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType } from 'vue';\nimport { UserDBInterface } from '@vue-skuilder/db';\nimport { alertUser } from '../SnackbarService';\nimport { Status, log } from '@vue-skuilder/common';\nimport { getCurrentUser, useAuthStore } from '../../stores/useAuthStore';\nimport { sendVerificationEmail } from '../../services/authAPI';\nimport { validatePassword } from '../../utils/passwordValidation';\n\nexport default defineComponent({\n name: 'UserRegistration',\n\n props: {\n onSignupSuccess: {\n type: Function as PropType<(payload: { username: string }) => void>,\n required: false,\n },\n },\n\n emits: ['toggle', 'signup-success'],\n\n data() {\n return {\n email: '',\n username: '',\n password: '',\n retypedPassword: '',\n passwordVisible: false,\n emailError: false,\n emailHint: '',\n usernameValidationInProgress: false,\n usernameError: false,\n usernameHint: '',\n awaitingResponse: false,\n badLoginAttempt: false,\n userSecret: '',\n secret: 'goons',\n user: null as UserDBInterface | null,\n roles: ['Student', 'Teacher', 'Author'] as string[],\n student: true,\n teacher: false,\n author: false,\n authStore: useAuthStore(),\n };\n },\n\n computed: {\n registrationRoute(): boolean {\n return typeof this.$route.name === 'string' && this.$route.name.toLowerCase() === 'signup';\n },\n buttonStatus() {\n return {\n color: this.badLoginAttempt ? 'error' : 'success',\n text: this.badLoginAttempt ? 'Try again' : 'Log In',\n };\n },\n passwordError(): string {\n return validatePassword(this.password);\n },\n passwordRetypeError(): string {\n console.log('[RTE]');\n if (this.password !== this.retypedPassword) {\n return 'Passwords must match.';\n } else {\n return '';\n }\n },\n },\n\n async created() {\n this.user = await getCurrentUser();\n },\n\n methods: {\n toggle() {\n log('Toggling registration / login forms.');\n this.$emit('toggle');\n },\n\n validateEmail() {\n this.emailError = false;\n // Basic email validation\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (this.email && !emailRegex.test(this.email)) {\n this.emailError = true;\n this.emailHint = 'Please enter a valid email address';\n } else {\n this.emailHint = '';\n }\n },\n\n validateUsername() {\n this.usernameError = false;\n },\n\n async createUser() {\n this.awaitingResponse = true;\n\n // Validate password before proceeding\n if (this.passwordError) {\n alertUser({\n text: this.passwordError,\n status: Status.error,\n });\n this.awaitingResponse = false;\n return;\n }\n\n log(`\nUser creation\n-------------\n\nName: ${this.username}\nStudent: ${this.student}\nTeacher: ${this.teacher}\nAuthor: ${this.author}\n`);\n if (this.password === this.retypedPassword) {\n if (!this.user) {\n console.error('ERROR: No user object available');\n return;\n }\n\n this.user\n .createAccount(this.username, this.password)\n .then(async (resp: any) => {\n if (resp.status === Status.ok) {\n // Account created successfully via PouchDB\n this.authStore.loginAndRegistration.loggedIn = true;\n this.authStore.loginAndRegistration.init = false;\n this.authStore.loginAndRegistration.init = true;\n\n // Send verification email if an address was provided. The address\n // is persisted to the _users doc by send-verification (the single\n // source of truth); no separate CONFIG.email copy is kept.\n if (this.email) {\n try {\n // Trigger verification email send with current origin\n const origin = typeof window !== 'undefined' ? window.location.origin : undefined;\n const verificationResult = await sendVerificationEmail(this.username, this.email, origin);\n if (verificationResult.ok) {\n alertUser({\n text: 'Account created! Please check your email to verify your account.',\n status: Status.ok,\n });\n } else {\n log(`Warning: Failed to send verification email: ${verificationResult.error}`);\n // Continue anyway - user can still use the account\n }\n } catch (emailError) {\n console.error('Email save/send error:', emailError);\n log(`Warning: Failed to save email or send verification: ${emailError}`);\n // Continue anyway - account was created successfully\n }\n }\n\n // Emit signup success event for parent to handle\n // Use the username we just created rather than calling getCurrentUser() again\n // which can fail if the auth state hasn't fully synchronized\n\n // Call callback prop if provided (preferred method)\n if (this.onSignupSuccess) {\n console.log('[UserRegistration] Calling onSignupSuccess callback');\n this.onSignupSuccess({ username: this.username });\n }\n\n // Also emit for backward compatibility\n this.$emit('signup-success', { username: this.username });\n } else {\n if (resp.error === 'This username is taken!') {\n this.usernameError = true;\n this.usernameHint = 'Try a different name.';\n (this.$refs.userNameTextField as HTMLInputElement).focus();\n alertUser({\n text: `The name ${this.username} is taken!`,\n status: resp.status,\n });\n } else {\n alertUser({\n text: resp.error,\n status: resp.status,\n });\n }\n }\n })\n .catch((e) => {\n console.error('[UserRegistration] .catch() called with error:', e);\n if (e) {\n const errorText = e?.message || e?.error || e?.toString() || 'Account creation failed';\n alertUser({\n text: errorText,\n status: Status.error,\n });\n }\n });\n this.awaitingResponse = false;\n } else {\n alertUser({\n text: 'Passwords do not match.',\n status: Status.error,\n });\n this.awaitingResponse = false;\n }\n },\n },\n});\n</script>\n"],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
3
+ import t from "./VerifyEmail.vue_vue_type_script_lang.mjs";
4
+ import { createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, openBlock as c, renderSlot as l, resolveComponent as u, toDisplayString as d, withCtx as f } from "vue";
5
+ //#region src/components/auth/VerifyEmail.vue
6
+ var p = {
7
+ key: 0,
8
+ class: "text-center"
9
+ }, m = {
10
+ key: 1,
11
+ class: "text-center"
12
+ }, h = { key: 0 }, g = {
13
+ key: 2,
14
+ class: "text-center"
15
+ }, _ = {
16
+ key: 3,
17
+ class: "text-center"
18
+ };
19
+ function _sfc_render(e, t, v, y, b, x) {
20
+ let S = u("v-card-title"), C = u("v-progress-circular"), w = u("v-icon"), T = u("v-card-text"), E = u("v-spacer"), D = u("v-btn"), O = u("v-card-actions"), k = u("v-card"), A = u("v-col"), j = u("v-row"), M = u("v-container");
21
+ return c(), n(M, {
22
+ class: "fill-height",
23
+ fluid: ""
24
+ }, {
25
+ default: f(() => [s(j, {
26
+ align: "center",
27
+ justify: "center"
28
+ }, {
29
+ default: f(() => [s(A, {
30
+ cols: "12",
31
+ sm: "8",
32
+ md: "6"
33
+ }, {
34
+ default: f(() => [s(k, null, {
35
+ default: f(() => [
36
+ s(S, { class: "text-h5 bg-grey-lighten-2" }, {
37
+ default: f(() => t[2] || (t[2] = [o(" Email Verification ")])),
38
+ _: 1
39
+ }),
40
+ s(T, { class: "pa-6" }, {
41
+ default: f(() => [e.isVerifying ? (c(), i("div", p, [s(C, {
42
+ indeterminate: "",
43
+ color: "primary",
44
+ size: "64",
45
+ class: "mb-4"
46
+ }), t[3] || (t[3] = a("p", null, "Verifying your email...", -1))])) : e.verificationStatus === "success" ? (c(), i("div", m, [
47
+ s(w, {
48
+ color: "success",
49
+ size: "64",
50
+ class: "mb-4"
51
+ }, {
52
+ default: f(() => t[4] || (t[4] = [o("mdi-check-circle")])),
53
+ _: 1
54
+ }),
55
+ t[5] || (t[5] = a("h3", { class: "mb-2" }, "Email Verified!", -1)),
56
+ t[6] || (t[6] = a("p", null, "Your account has been successfully verified.", -1)),
57
+ e.username ? (c(), i("p", h, "Welcome, " + d(e.username) + "!", 1)) : r("", !0)
58
+ ])) : e.verificationStatus === "error" ? (c(), i("div", g, [
59
+ s(w, {
60
+ color: "error",
61
+ size: "64",
62
+ class: "mb-4"
63
+ }, {
64
+ default: f(() => t[7] || (t[7] = [o("mdi-alert-circle")])),
65
+ _: 1
66
+ }),
67
+ t[8] || (t[8] = a("h3", { class: "mb-2" }, "Verification Failed", -1)),
68
+ a("p", null, d(e.errorMessage), 1)
69
+ ])) : (c(), i("div", _, [
70
+ s(w, {
71
+ color: "warning",
72
+ size: "64",
73
+ class: "mb-4"
74
+ }, {
75
+ default: f(() => t[9] || (t[9] = [o("mdi-help-circle")])),
76
+ _: 1
77
+ }),
78
+ t[10] || (t[10] = a("h3", { class: "mb-2" }, "No Verification Token", -1)),
79
+ t[11] || (t[11] = a("p", null, "Please use the link from your verification email.", -1))
80
+ ]))]),
81
+ _: 1
82
+ }),
83
+ s(O, null, {
84
+ default: f(() => [s(E), l(e.$slots, "actions", {
85
+ status: e.verificationStatus,
86
+ username: e.username
87
+ }, () => [e.verificationStatus === "success" ? (c(), n(D, {
88
+ key: 0,
89
+ color: "primary",
90
+ onClick: t[0] || (t[0] = (t) => e.$emit("verified", e.username))
91
+ }, {
92
+ default: f(() => t[12] || (t[12] = [o(" Continue ")])),
93
+ _: 1
94
+ })) : e.verificationStatus === "error" ? (c(), n(D, {
95
+ key: 1,
96
+ variant: "text",
97
+ onClick: t[1] || (t[1] = (t) => e.$emit("error", e.errorMessage))
98
+ }, {
99
+ default: f(() => t[13] || (t[13] = [o(" Close ")])),
100
+ _: 1
101
+ })) : r("", !0)])]),
102
+ _: 3
103
+ })
104
+ ]),
105
+ _: 3
106
+ })]),
107
+ _: 3
108
+ })]),
109
+ _: 3
110
+ })]),
111
+ _: 3
112
+ });
113
+ }
114
+ var v = /* @__PURE__ */ e(t, [["render", _sfc_render]]);
115
+ //#endregion
116
+ export { v as default };
117
+
118
+ //# sourceMappingURL=VerifyEmail.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VerifyEmail.mjs","names":[],"sources":["../../../src/components/auth/VerifyEmail.vue"],"sourcesContent":["<template>\n <v-container class=\"fill-height\" fluid>\n <v-row align=\"center\" justify=\"center\">\n <v-col cols=\"12\" sm=\"8\" md=\"6\">\n <v-card>\n <v-card-title class=\"text-h5 bg-grey-lighten-2\">\n Email Verification\n </v-card-title>\n\n <v-card-text class=\"pa-6\">\n <!-- Loading state -->\n <div v-if=\"isVerifying\" class=\"text-center\">\n <v-progress-circular\n indeterminate\n color=\"primary\"\n size=\"64\"\n class=\"mb-4\"\n ></v-progress-circular>\n <p>Verifying your email...</p>\n </div>\n\n <!-- Success state -->\n <div v-else-if=\"verificationStatus === 'success'\" class=\"text-center\">\n <v-icon color=\"success\" size=\"64\" class=\"mb-4\">mdi-check-circle</v-icon>\n <h3 class=\"mb-2\">Email Verified!</h3>\n <p>Your account has been successfully verified.</p>\n <p v-if=\"username\">Welcome, {{ username }}!</p>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"verificationStatus === 'error'\" class=\"text-center\">\n <v-icon color=\"error\" size=\"64\" class=\"mb-4\">mdi-alert-circle</v-icon>\n <h3 class=\"mb-2\">Verification Failed</h3>\n <p>{{ errorMessage }}</p>\n </div>\n\n <!-- No token state -->\n <div v-else class=\"text-center\">\n <v-icon color=\"warning\" size=\"64\" class=\"mb-4\">mdi-help-circle</v-icon>\n <h3 class=\"mb-2\">No Verification Token</h3>\n <p>Please use the link from your verification email.</p>\n </div>\n </v-card-text>\n\n <v-card-actions>\n <v-spacer></v-spacer>\n <slot name=\"actions\" :status=\"verificationStatus\" :username=\"username\">\n <!-- Default action - external apps can override with their own navigation -->\n <v-btn\n v-if=\"verificationStatus === 'success'\"\n color=\"primary\"\n @click=\"$emit('verified', username)\"\n >\n Continue\n </v-btn>\n <v-btn\n v-else-if=\"verificationStatus === 'error'\"\n variant=\"text\"\n @click=\"$emit('error', errorMessage)\"\n >\n Close\n </v-btn>\n </slot>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { verifyEmail } from '../../services/authAPI';\nimport { alertUser } from '../SnackbarService';\nimport { Status } from '@vue-skuilder/common';\n\nexport default defineComponent({\n name: 'VerifyEmail',\n\n emits: ['verified', 'error'],\n\n props: {\n /**\n * Verification token. If not provided, will try to read from URL query params.\n */\n token: {\n type: String,\n default: null,\n },\n },\n\n data() {\n return {\n isVerifying: false,\n verificationStatus: null as 'success' | 'error' | null,\n errorMessage: '',\n username: '',\n };\n },\n\n async mounted() {\n await this.performVerification();\n },\n\n methods: {\n async performVerification() {\n // Get token from prop or URL query params\n const token = this.token || this.getTokenFromURL();\n\n if (!token) {\n this.verificationStatus = 'error';\n this.errorMessage = 'No verification token provided';\n return;\n }\n\n this.isVerifying = true;\n\n try {\n const result = await verifyEmail(token);\n\n if (result.ok) {\n this.verificationStatus = 'success';\n this.username = result.username || '';\n alertUser({\n text: 'Email verified successfully!',\n status: Status.ok,\n });\n } else {\n this.verificationStatus = 'error';\n this.errorMessage = result.error || 'Verification failed';\n alertUser({\n text: result.error || 'Verification failed',\n status: Status.error,\n });\n }\n } catch (error) {\n this.verificationStatus = 'error';\n this.errorMessage = 'An unexpected error occurred';\n alertUser({\n text: 'An unexpected error occurred',\n status: Status.error,\n });\n } finally {\n this.isVerifying = false;\n }\n },\n\n getTokenFromURL(): string | null {\n if (typeof window === 'undefined') return null;\n\n const params = new URLSearchParams(window.location.search);\n return params.get('token');\n },\n },\n});\n</script>\n"],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import { alertUser as e } from "../SnackbarService.mjs";
3
+ import { verifyEmail as t } from "../../services/authAPI.mjs";
4
+ import { defineComponent as n } from "vue";
5
+ import { Status as r } from "@vue-skuilder/common";
6
+ //#region src/components/auth/VerifyEmail.vue?vue&type=script&lang.ts
7
+ var i = n({
8
+ name: "VerifyEmail",
9
+ emits: ["verified", "error"],
10
+ props: { token: {
11
+ type: String,
12
+ default: null
13
+ } },
14
+ data() {
15
+ return {
16
+ isVerifying: !1,
17
+ verificationStatus: null,
18
+ errorMessage: "",
19
+ username: ""
20
+ };
21
+ },
22
+ async mounted() {
23
+ await this.performVerification();
24
+ },
25
+ methods: {
26
+ async performVerification() {
27
+ let n = this.token || this.getTokenFromURL();
28
+ if (!n) {
29
+ this.verificationStatus = "error", this.errorMessage = "No verification token provided";
30
+ return;
31
+ }
32
+ this.isVerifying = !0;
33
+ try {
34
+ let i = await t(n);
35
+ i.ok ? (this.verificationStatus = "success", this.username = i.username || "", e({
36
+ text: "Email verified successfully!",
37
+ status: r.ok
38
+ })) : (this.verificationStatus = "error", this.errorMessage = i.error || "Verification failed", e({
39
+ text: i.error || "Verification failed",
40
+ status: r.error
41
+ }));
42
+ } catch {
43
+ this.verificationStatus = "error", this.errorMessage = "An unexpected error occurred", e({
44
+ text: "An unexpected error occurred",
45
+ status: r.error
46
+ });
47
+ } finally {
48
+ this.isVerifying = !1;
49
+ }
50
+ },
51
+ getTokenFromURL() {
52
+ return typeof window > "u" ? null : new URLSearchParams(window.location.search).get("token");
53
+ }
54
+ }
55
+ });
56
+ //#endregion
57
+ export { i as default };
58
+
59
+ //# sourceMappingURL=VerifyEmail.vue_vue_type_script_lang.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VerifyEmail.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/auth/VerifyEmail.vue"],"sourcesContent":["<template>\n <v-container class=\"fill-height\" fluid>\n <v-row align=\"center\" justify=\"center\">\n <v-col cols=\"12\" sm=\"8\" md=\"6\">\n <v-card>\n <v-card-title class=\"text-h5 bg-grey-lighten-2\">\n Email Verification\n </v-card-title>\n\n <v-card-text class=\"pa-6\">\n <!-- Loading state -->\n <div v-if=\"isVerifying\" class=\"text-center\">\n <v-progress-circular\n indeterminate\n color=\"primary\"\n size=\"64\"\n class=\"mb-4\"\n ></v-progress-circular>\n <p>Verifying your email...</p>\n </div>\n\n <!-- Success state -->\n <div v-else-if=\"verificationStatus === 'success'\" class=\"text-center\">\n <v-icon color=\"success\" size=\"64\" class=\"mb-4\">mdi-check-circle</v-icon>\n <h3 class=\"mb-2\">Email Verified!</h3>\n <p>Your account has been successfully verified.</p>\n <p v-if=\"username\">Welcome, {{ username }}!</p>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"verificationStatus === 'error'\" class=\"text-center\">\n <v-icon color=\"error\" size=\"64\" class=\"mb-4\">mdi-alert-circle</v-icon>\n <h3 class=\"mb-2\">Verification Failed</h3>\n <p>{{ errorMessage }}</p>\n </div>\n\n <!-- No token state -->\n <div v-else class=\"text-center\">\n <v-icon color=\"warning\" size=\"64\" class=\"mb-4\">mdi-help-circle</v-icon>\n <h3 class=\"mb-2\">No Verification Token</h3>\n <p>Please use the link from your verification email.</p>\n </div>\n </v-card-text>\n\n <v-card-actions>\n <v-spacer></v-spacer>\n <slot name=\"actions\" :status=\"verificationStatus\" :username=\"username\">\n <!-- Default action - external apps can override with their own navigation -->\n <v-btn\n v-if=\"verificationStatus === 'success'\"\n color=\"primary\"\n @click=\"$emit('verified', username)\"\n >\n Continue\n </v-btn>\n <v-btn\n v-else-if=\"verificationStatus === 'error'\"\n variant=\"text\"\n @click=\"$emit('error', errorMessage)\"\n >\n Close\n </v-btn>\n </slot>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { verifyEmail } from '../../services/authAPI';\nimport { alertUser } from '../SnackbarService';\nimport { Status } from '@vue-skuilder/common';\n\nexport default defineComponent({\n name: 'VerifyEmail',\n\n emits: ['verified', 'error'],\n\n props: {\n /**\n * Verification token. If not provided, will try to read from URL query params.\n */\n token: {\n type: String,\n default: null,\n },\n },\n\n data() {\n return {\n isVerifying: false,\n verificationStatus: null as 'success' | 'error' | null,\n errorMessage: '',\n username: '',\n };\n },\n\n async mounted() {\n await this.performVerification();\n },\n\n methods: {\n async performVerification() {\n // Get token from prop or URL query params\n const token = this.token || this.getTokenFromURL();\n\n if (!token) {\n this.verificationStatus = 'error';\n this.errorMessage = 'No verification token provided';\n return;\n }\n\n this.isVerifying = true;\n\n try {\n const result = await verifyEmail(token);\n\n if (result.ok) {\n this.verificationStatus = 'success';\n this.username = result.username || '';\n alertUser({\n text: 'Email verified successfully!',\n status: Status.ok,\n });\n } else {\n this.verificationStatus = 'error';\n this.errorMessage = result.error || 'Verification failed';\n alertUser({\n text: result.error || 'Verification failed',\n status: Status.error,\n });\n }\n } catch (error) {\n this.verificationStatus = 'error';\n this.errorMessage = 'An unexpected error occurred';\n alertUser({\n text: 'An unexpected error occurred',\n status: Status.error,\n });\n } finally {\n this.isVerifying = false;\n }\n },\n\n getTokenFromURL(): string | null {\n if (typeof window === 'undefined') return null;\n\n const params = new URLSearchParams(window.location.search);\n return params.get('token');\n },\n },\n});\n</script>\n"],"mappings":";;;;;;AA4EA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,OAAO,CAAC,YAAY,QAAQ;CAE5B,OAAO,EAIL,OAAO;EACL,MAAM;EACN,SAAS;EACV,EACF;CAED,OAAO;AACL,SAAO;GACL,aAAa;GACb,oBAAoB;GACpB,cAAc;GACd,UAAU;GACX;;CAGH,MAAM,UAAU;AACd,QAAM,KAAK,qBAAqB;;CAGlC,SAAS;EACP,MAAM,sBAAsB;GAE1B,IAAM,IAAQ,KAAK,SAAS,KAAK,iBAAiB;AAElD,OAAI,CAAC,GAAO;AAEV,IADA,KAAK,qBAAqB,SAC1B,KAAK,eAAe;AACpB;;AAGF,QAAK,cAAc;AAEnB,OAAI;IACF,IAAM,IAAS,MAAM,EAAY,EAAM;AAEvC,IAAI,EAAO,MACT,KAAK,qBAAqB,WAC1B,KAAK,WAAW,EAAO,YAAY,IACnC,EAAU;KACR,MAAM;KACN,QAAQ,EAAO;KAChB,CAAC,KAEF,KAAK,qBAAqB,SAC1B,KAAK,eAAe,EAAO,SAAS,uBACpC,EAAU;KACR,MAAM,EAAO,SAAS;KACtB,QAAQ,EAAO;KAChB,CAAC;WAEU;AAGd,IAFA,KAAK,qBAAqB,SAC1B,KAAK,eAAe,gCACpB,EAAU;KACR,MAAM;KACN,QAAQ,EAAO;KAChB,CAAC;aACM;AACR,SAAK,cAAc;;;EAIvB,kBAAiC;AAI/B,UAHI,OAAO,SAAW,MAAoB,OAE3B,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ;;EAE7B;CACF,CAAC"}
@@ -0,0 +1,9 @@
1
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
2
+ import t from "./AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs";
3
+ /* empty css */
4
+ //#region src/components/cardRendering/AudioAutoPlayer.vue
5
+ var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-e1a0f62c"]]);
6
+ //#endregion
7
+ export { n as default };
8
+
9
+ //# sourceMappingURL=AudioAutoPlayer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioAutoPlayer.mjs","names":[],"sources":["../../../src/components/cardRendering/AudioAutoPlayer.vue"],"sourcesContent":["<template>\n <v-btn size=\"large\" icon :color=\"playing ? 'primary lighten-3' : 'primary'\" :class=\"{ playing }\" @click=\"play\">\n <v-icon>mdi-volume-high</v-icon>\n </v-btn>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onBeforeUnmount, onMounted, getCurrentInstance } from 'vue';\nimport { SkldrMouseTrap } from '../../utils/SkldrMouseTrap';\n\nconst props = defineProps<{\n src: string | string[];\n}>();\n\nconst audioElems = ref<HTMLAudioElement[]>([]);\nconst playTimeouts = ref<NodeJS.Timer[]>([]);\nconst playing = ref(false);\n\nlet staticLOCK: any = null;\nconst playbackGap = 500;\n\nconst stop = () => {\n playing.value = false;\n setTimeout(() => {\n staticLOCK = null;\n }, playbackGap);\n\n playTimeouts.value.forEach(clearTimeout);\n\n console.log(`Audio stopping...`);\n audioElems.value.forEach((audio) => {\n if (!audio.paused) {\n audio.pause();\n audio.currentTime = 0;\n }\n });\n};\n\nconst downloadFinished = (i: number): boolean => {\n try {\n return !isNaN(audioElems.value[i].duration);\n } catch (e) {\n throw new Error('AudioPlayer does not have an element at this index:', e);\n }\n};\n\nconst playByIndex = (n: number) => {\n if (downloadFinished(n)) {\n audioElems.value[n].play();\n\n if (n + 1 < audioElems.value.length) {\n const delay = (audioElems.value[n].duration + 0.7) * 1000;\n playTimeouts.value.push(\n setTimeout(() => {\n if (playing.value) {\n playByIndex(n + 1);\n }\n }, delay)\n );\n } else {\n setTimeout(() => {\n playing.value = false;\n }, audioElems.value[n].duration * 1000);\n setTimeout(() => {\n staticLOCK = null;\n }, audioElems.value[n].duration * 1000 + playbackGap);\n }\n } else {\n setTimeout(playByIndex, 100, n);\n }\n};\n\nconst play = () => {\n if (staticLOCK === null || staticLOCK === getCurrentInstance()) {\n staticLOCK = getCurrentInstance();\n playing.value = true;\n playByIndex(0);\n } else {\n setTimeout(play, 100);\n }\n};\n\nonMounted(() => {\n staticLOCK = null;\n\n if (typeof props.src === 'string') {\n audioElems.value.push(new Audio(props.src));\n } else {\n props.src.forEach((url) => {\n audioElems.value.push(new Audio(url));\n });\n }\n\n // Define hotkeys\n const hotkeys = [\n {\n hotkey: 'up',\n callback: play,\n command: 'Replay Audio',\n },\n ];\n \n // Add bindings\n SkldrMouseTrap.addBinding(hotkeys);\n\n play();\n});\n\nonBeforeUnmount(() => {\n // Clean up hotkey bindings\n SkldrMouseTrap.removeBinding('up');\n stop();\n});\n</script>\n\n<style scoped>\n.playing {\n /* transform: rotate(3deg) scale(1.15); */\n animation: 0.85s ease-in-out infinite alternate pulse;\n z-index: 1;\n}\n\n@keyframes pulse {\n 0% {\n transform: scale(1);\n }\n 100% {\n transform: scale(1.15);\n }\n}\n</style>\n"],"mappings":""}
@@ -0,0 +1,69 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import { SkldrMouseTrap as e } from "../../utils/SkldrMouseTrap.mjs";
3
+ import { createBlock as t, createTextVNode as n, createVNode as r, defineComponent as i, getCurrentInstance as a, normalizeClass as o, onBeforeUnmount as s, onMounted as c, openBlock as l, ref as u, resolveComponent as d, withCtx as f } from "vue";
4
+ //#region src/components/cardRendering/AudioAutoPlayer.vue?vue&type=script&setup=true&lang.ts
5
+ var p = 500, m = /* @__PURE__ */ i({
6
+ __name: "AudioAutoPlayer",
7
+ props: { src: {} },
8
+ setup(i) {
9
+ let m = i, h = u([]), g = u([]), _ = u(!1), v = null, stop = () => {
10
+ _.value = !1, setTimeout(() => {
11
+ v = null;
12
+ }, p), g.value.forEach(clearTimeout), console.log("Audio stopping..."), h.value.forEach((e) => {
13
+ e.paused || (e.pause(), e.currentTime = 0);
14
+ });
15
+ }, downloadFinished = (e) => {
16
+ try {
17
+ return !isNaN(h.value[e].duration);
18
+ } catch (e) {
19
+ throw Error("AudioPlayer does not have an element at this index:", e);
20
+ }
21
+ }, playByIndex = (e) => {
22
+ if (downloadFinished(e)) if (h.value[e].play(), e + 1 < h.value.length) {
23
+ let t = (h.value[e].duration + .7) * 1e3;
24
+ g.value.push(setTimeout(() => {
25
+ _.value && playByIndex(e + 1);
26
+ }, t));
27
+ } else setTimeout(() => {
28
+ _.value = !1;
29
+ }, h.value[e].duration * 1e3), setTimeout(() => {
30
+ v = null;
31
+ }, h.value[e].duration * 1e3 + p);
32
+ else setTimeout(playByIndex, 100, e);
33
+ }, play = () => {
34
+ v === null || v === a() ? (v = a(), _.value = !0, playByIndex(0)) : setTimeout(play, 100);
35
+ };
36
+ return c(() => {
37
+ v = null, typeof m.src == "string" ? h.value.push(new Audio(m.src)) : m.src.forEach((e) => {
38
+ h.value.push(new Audio(e));
39
+ });
40
+ let t = [{
41
+ hotkey: "up",
42
+ callback: play,
43
+ command: "Replay Audio"
44
+ }];
45
+ e.addBinding(t), play();
46
+ }), s(() => {
47
+ e.removeBinding("up"), stop();
48
+ }), (e, i) => {
49
+ let a = d("v-icon"), s = d("v-btn");
50
+ return l(), t(s, {
51
+ size: "large",
52
+ icon: "",
53
+ color: _.value ? "primary lighten-3" : "primary",
54
+ class: o({ playing: _.value }),
55
+ onClick: play
56
+ }, {
57
+ default: f(() => [r(a, null, {
58
+ default: f(() => i[0] || (i[0] = [n("mdi-volume-high")])),
59
+ _: 1
60
+ })]),
61
+ _: 1
62
+ }, 8, ["color", "class"]);
63
+ };
64
+ }
65
+ });
66
+ //#endregion
67
+ export { m as default };
68
+
69
+ //# sourceMappingURL=AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs","names":[],"sources":["../../../src/components/cardRendering/AudioAutoPlayer.vue"],"sourcesContent":["<template>\n <v-btn size=\"large\" icon :color=\"playing ? 'primary lighten-3' : 'primary'\" :class=\"{ playing }\" @click=\"play\">\n <v-icon>mdi-volume-high</v-icon>\n </v-btn>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onBeforeUnmount, onMounted, getCurrentInstance } from 'vue';\nimport { SkldrMouseTrap } from '../../utils/SkldrMouseTrap';\n\nconst props = defineProps<{\n src: string | string[];\n}>();\n\nconst audioElems = ref<HTMLAudioElement[]>([]);\nconst playTimeouts = ref<NodeJS.Timer[]>([]);\nconst playing = ref(false);\n\nlet staticLOCK: any = null;\nconst playbackGap = 500;\n\nconst stop = () => {\n playing.value = false;\n setTimeout(() => {\n staticLOCK = null;\n }, playbackGap);\n\n playTimeouts.value.forEach(clearTimeout);\n\n console.log(`Audio stopping...`);\n audioElems.value.forEach((audio) => {\n if (!audio.paused) {\n audio.pause();\n audio.currentTime = 0;\n }\n });\n};\n\nconst downloadFinished = (i: number): boolean => {\n try {\n return !isNaN(audioElems.value[i].duration);\n } catch (e) {\n throw new Error('AudioPlayer does not have an element at this index:', e);\n }\n};\n\nconst playByIndex = (n: number) => {\n if (downloadFinished(n)) {\n audioElems.value[n].play();\n\n if (n + 1 < audioElems.value.length) {\n const delay = (audioElems.value[n].duration + 0.7) * 1000;\n playTimeouts.value.push(\n setTimeout(() => {\n if (playing.value) {\n playByIndex(n + 1);\n }\n }, delay)\n );\n } else {\n setTimeout(() => {\n playing.value = false;\n }, audioElems.value[n].duration * 1000);\n setTimeout(() => {\n staticLOCK = null;\n }, audioElems.value[n].duration * 1000 + playbackGap);\n }\n } else {\n setTimeout(playByIndex, 100, n);\n }\n};\n\nconst play = () => {\n if (staticLOCK === null || staticLOCK === getCurrentInstance()) {\n staticLOCK = getCurrentInstance();\n playing.value = true;\n playByIndex(0);\n } else {\n setTimeout(play, 100);\n }\n};\n\nonMounted(() => {\n staticLOCK = null;\n\n if (typeof props.src === 'string') {\n audioElems.value.push(new Audio(props.src));\n } else {\n props.src.forEach((url) => {\n audioElems.value.push(new Audio(url));\n });\n }\n\n // Define hotkeys\n const hotkeys = [\n {\n hotkey: 'up',\n callback: play,\n command: 'Replay Audio',\n },\n ];\n \n // Add bindings\n SkldrMouseTrap.addBinding(hotkeys);\n\n play();\n});\n\nonBeforeUnmount(() => {\n // Clean up hotkey bindings\n SkldrMouseTrap.removeBinding('up');\n stop();\n});\n</script>\n\n<style scoped>\n.playing {\n /* transform: rotate(3deg) scale(1.15); */\n animation: 0.85s ease-in-out infinite alternate pulse;\n z-index: 1;\n}\n\n@keyframes pulse {\n 0% {\n transform: scale(1);\n }\n 100% {\n transform: scale(1.15);\n }\n}\n</style>\n"],"mappings":";;;;AAmBA,IAAM,IAAc;;;;EATpB,IAAM,IAAQ,GAIR,IAAa,EAAwB,EAAE,CAAC,EACxC,IAAe,EAAoB,EAAE,CAAC,EACtC,IAAU,EAAI,GAAM,EAEtB,IAAkB,MAGhB,aAAa;AASjB,GARA,EAAQ,QAAQ,IAChB,iBAAiB;AACf,QAAa;MACZ,EAAY,EAEf,EAAa,MAAM,QAAQ,aAAa,EAExC,QAAQ,IAAI,oBAAoB,EAChC,EAAW,MAAM,SAAS,MAAU;AAClC,IAAK,EAAM,WACT,EAAM,OAAO,EACb,EAAM,cAAc;KAEtB;KAGE,oBAAoB,MAAuB;AAC/C,OAAI;AACF,WAAO,CAAC,MAAM,EAAW,MAAM,GAAG,SAAS;YACpC,GAAG;AACV,UAAU,MAAM,uDAAuD,EAAE;;KAIvE,eAAe,MAAc;AACjC,OAAI,iBAAiB,EAAE,CAGrB,KAFA,EAAW,MAAM,GAAG,MAAM,EAEtB,IAAI,IAAI,EAAW,MAAM,QAAQ;IACnC,IAAM,KAAS,EAAW,MAAM,GAAG,WAAW,MAAO;AACrD,MAAa,MAAM,KACjB,iBAAiB;AACf,KAAI,EAAQ,SACV,YAAY,IAAI,EAAE;OAEnB,EAAK,CACT;SAKD,CAHA,iBAAiB;AACf,MAAQ,QAAQ;MACf,EAAW,MAAM,GAAG,WAAW,IAAK,EACvC,iBAAiB;AACf,QAAa;MACZ,EAAW,MAAM,GAAG,WAAW,MAAO,EAAY;OAGvD,YAAW,aAAa,KAAK,EAAE;KAI7B,aAAa;AACjB,GAAI,MAAe,QAAQ,MAAe,GAAoB,IAC5D,IAAa,GAAoB,EACjC,EAAQ,QAAQ,IAChB,YAAY,EAAE,IAEd,WAAW,MAAM,IAAI;;SAIzB,QAAgB;AAGd,GAFA,IAAa,MAET,OAAO,EAAM,OAAQ,WACvB,EAAW,MAAM,KAAK,IAAI,MAAM,EAAM,IAAI,CAAC,GAE3C,EAAM,IAAI,SAAS,MAAQ;AACzB,MAAW,MAAM,KAAK,IAAI,MAAM,EAAI,CAAC;KACrC;GAIJ,IAAM,IAAU,CACd;IACE,QAAQ;IACR,UAAU;IACV,SAAS;IACV,CACF;AAKD,GAFA,EAAe,WAAW,EAAQ,EAElC,MAAM;IACN,EAEF,QAAsB;AAGpB,GADA,EAAe,cAAc,KAAK,EAClC,MAAM;IACN"}
@@ -0,0 +1,31 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
3
+ import t from "./CardLoader.vue_vue_type_script_lang.mjs";
4
+ /* empty css */
5
+ import { createBlock as n, createCommentVNode as r, normalizeClass as i, openBlock as a, resolveComponent as o } from "vue";
6
+ //#region src/components/cardRendering/CardLoader.vue
7
+ function _sfc_render(e, t, s, c, l, u) {
8
+ let d = o("card-viewer");
9
+ return e.loading ? r("", !0) : (a(), n(d, {
10
+ key: 0,
11
+ class: i(["ma-2", e.loading ? "muted" : ""]),
12
+ view: e.view,
13
+ data: e.data,
14
+ card_id: e.cardID,
15
+ course_id: e.courseID,
16
+ "session-order": e.sessionOrder,
17
+ onEmitResponse: t[0] || (t[0] = (t) => e.processResponse(t))
18
+ }, null, 8, [
19
+ "class",
20
+ "view",
21
+ "data",
22
+ "card_id",
23
+ "course_id",
24
+ "session-order"
25
+ ]));
26
+ }
27
+ var s = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-93f758b5"]]);
28
+ //#endregion
29
+ export { s as default };
30
+
31
+ //# sourceMappingURL=CardLoader.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CardLoader.mjs","names":[],"sources":["../../../src/components/cardRendering/CardLoader.vue"],"sourcesContent":["<template>\n <card-viewer\n v-if=\"!loading\"\n class=\"ma-2\"\n :class=\"loading ? 'muted' : ''\"\n :view=\"view\"\n :data=\"data\"\n :card_id=\"cardID\"\n :course_id=\"courseID\"\n :session-order=\"sessionOrder\"\n @emit-response=\"processResponse($event)\"\n />\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType, markRaw } from 'vue';\nimport { getDataLayer, QualifiedCardID } from '@vue-skuilder/db';\nimport {\n log,\n displayableDataToViewData,\n ViewData,\n ViewDescriptor,\n CardData,\n CardRecord,\n DisplayableData,\n} from '@vue-skuilder/common';\nimport { ViewComponent } from '../../composables';\nimport CardViewer from './CardViewer.vue';\n\nexport default defineComponent({\n name: 'CardLoader',\n\n components: {\n CardViewer,\n },\n\n props: {\n sessionOrder: {\n type: Number,\n required: false,\n default: 0,\n },\n qualified_id: {\n type: Object as PropType<QualifiedCardID>,\n required: true,\n },\n viewLookup: {\n type: Function as PropType<(viewDescription: ViewDescriptor | string) => ViewComponent>,\n required: true,\n },\n },\n\n data() {\n return {\n loading: true,\n view: null as ViewComponent | null,\n data: [] as ViewData[],\n courseID: '',\n cardID: '',\n };\n },\n\n created() {\n this.loadCard();\n },\n\n watch: {\n qualified_id: {\n immediate: true,\n handler() {\n this.loadCard();\n },\n },\n },\n\n methods: {\n processResponse(r: CardRecord) {\n log(`\n Card was displayed at ${r.timeStamp}\n User spent ${r.timeSpent} milliseconds with the card.\n `);\n this.$emit('emitResponse', r);\n },\n\n async loadCard() {\n const qualified_id = this.qualified_id;\n console.log(`Card Loader displaying: ${qualified_id.courseID}::${qualified_id.cardID}`);\n\n this.loading = true;\n const _courseID = qualified_id.courseID;\n const _cardID = qualified_id.cardID;\n const courseDB = getDataLayer().getCourseDB(_courseID);\n\n try {\n const tmpCardData = (await courseDB.getCourseDoc(_cardID)) as CardData;\n const tmpView = this.viewLookup(tmpCardData.id_view);\n const tmpDataDocs = tmpCardData.id_displayable_data.map((id) => {\n return courseDB.getCourseDoc(id, {\n attachments: true,\n binary: true,\n });\n });\n\n const tmpData = [];\n\n for (const docPromise of tmpDataDocs) {\n const doc = (await docPromise) as DisplayableData;\n tmpData.unshift(displayableDataToViewData(doc));\n }\n\n this.data = tmpData;\n this.view = markRaw(tmpView as ViewComponent);\n this.cardID = _cardID;\n this.courseID = _courseID;\n } catch (e) {\n throw new Error(`[CardLoader] Error loading card: ${JSON.stringify(e)}, ${e}`);\n } finally {\n this.loading = false;\n this.$emit('card-loaded');\n }\n },\n },\n});\n</script>\n\n<style scoped>\n.cardView {\n padding: 15px;\n border-radius: 8px;\n}\n\n.component-fade-enter-active,\n.component-fade-leave-active {\n transition: opacity 0.3s ease;\n}\n.component-fade-enter, .component-fade-leave-to\n/* .component-fade-leave-active below version 2.1.8 */ {\n opacity: 0;\n}\n</style>\n"],"mappings":";;;;;;;;QAEW,EAAA,UAFX,EAAA,IAAA,GAAA,IAEW,GAAA,EADT,EAUE,GAAA;EAXJ,KAAA;EAGI,OAHJ,EAAA,CAGU,QACE,EAAA,UAAO,UAAA,GAAA,CAAA;EACd,MAAM,EAAA;EACN,MAAM,EAAA;EACN,SAAS,EAAA;EACT,WAAW,EAAA;EACX,iBAAe,EAAA;EACf,gBAAa,EAAA,OAAA,EAAA,MAAA,MAAE,EAAA,gBAAgB,EAAM"}
@@ -0,0 +1,75 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import e from "./CardViewer.mjs";
3
+ import { defineComponent as t, markRaw as n } from "vue";
4
+ import { displayableDataToViewData as r, log as i } from "@vue-skuilder/common";
5
+ import { getDataLayer as a } from "@vue-skuilder/db";
6
+ //#region src/components/cardRendering/CardLoader.vue?vue&type=script&lang.ts
7
+ var o = t({
8
+ name: "CardLoader",
9
+ components: { CardViewer: e },
10
+ props: {
11
+ sessionOrder: {
12
+ type: Number,
13
+ required: !1,
14
+ default: 0
15
+ },
16
+ qualified_id: {
17
+ type: Object,
18
+ required: !0
19
+ },
20
+ viewLookup: {
21
+ type: Function,
22
+ required: !0
23
+ }
24
+ },
25
+ data() {
26
+ return {
27
+ loading: !0,
28
+ view: null,
29
+ data: [],
30
+ courseID: "",
31
+ cardID: ""
32
+ };
33
+ },
34
+ created() {
35
+ this.loadCard();
36
+ },
37
+ watch: { qualified_id: {
38
+ immediate: !0,
39
+ handler() {
40
+ this.loadCard();
41
+ }
42
+ } },
43
+ methods: {
44
+ processResponse(e) {
45
+ i(`
46
+ Card was displayed at ${e.timeStamp}
47
+ User spent ${e.timeSpent} milliseconds with the card.
48
+ `), this.$emit("emitResponse", e);
49
+ },
50
+ async loadCard() {
51
+ let e = this.qualified_id;
52
+ console.log(`Card Loader displaying: ${e.courseID}::${e.cardID}`), this.loading = !0;
53
+ let t = e.courseID, i = e.cardID, o = a().getCourseDB(t);
54
+ try {
55
+ let e = await o.getCourseDoc(i), a = this.viewLookup(e.id_view), s = e.id_displayable_data.map((e) => o.getCourseDoc(e, {
56
+ attachments: !0,
57
+ binary: !0
58
+ })), c = [];
59
+ for (let e of s) {
60
+ let t = await e;
61
+ c.unshift(r(t));
62
+ }
63
+ this.data = c, this.view = n(a), this.cardID = i, this.courseID = t;
64
+ } catch (e) {
65
+ throw Error(`[CardLoader] Error loading card: ${JSON.stringify(e)}, ${e}`);
66
+ } finally {
67
+ this.loading = !1, this.$emit("card-loaded");
68
+ }
69
+ }
70
+ }
71
+ });
72
+ //#endregion
73
+ export { o as default };
74
+
75
+ //# sourceMappingURL=CardLoader.vue_vue_type_script_lang.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CardLoader.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/cardRendering/CardLoader.vue"],"sourcesContent":["<template>\n <card-viewer\n v-if=\"!loading\"\n class=\"ma-2\"\n :class=\"loading ? 'muted' : ''\"\n :view=\"view\"\n :data=\"data\"\n :card_id=\"cardID\"\n :course_id=\"courseID\"\n :session-order=\"sessionOrder\"\n @emit-response=\"processResponse($event)\"\n />\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType, markRaw } from 'vue';\nimport { getDataLayer, QualifiedCardID } from '@vue-skuilder/db';\nimport {\n log,\n displayableDataToViewData,\n ViewData,\n ViewDescriptor,\n CardData,\n CardRecord,\n DisplayableData,\n} from '@vue-skuilder/common';\nimport { ViewComponent } from '../../composables';\nimport CardViewer from './CardViewer.vue';\n\nexport default defineComponent({\n name: 'CardLoader',\n\n components: {\n CardViewer,\n },\n\n props: {\n sessionOrder: {\n type: Number,\n required: false,\n default: 0,\n },\n qualified_id: {\n type: Object as PropType<QualifiedCardID>,\n required: true,\n },\n viewLookup: {\n type: Function as PropType<(viewDescription: ViewDescriptor | string) => ViewComponent>,\n required: true,\n },\n },\n\n data() {\n return {\n loading: true,\n view: null as ViewComponent | null,\n data: [] as ViewData[],\n courseID: '',\n cardID: '',\n };\n },\n\n created() {\n this.loadCard();\n },\n\n watch: {\n qualified_id: {\n immediate: true,\n handler() {\n this.loadCard();\n },\n },\n },\n\n methods: {\n processResponse(r: CardRecord) {\n log(`\n Card was displayed at ${r.timeStamp}\n User spent ${r.timeSpent} milliseconds with the card.\n `);\n this.$emit('emitResponse', r);\n },\n\n async loadCard() {\n const qualified_id = this.qualified_id;\n console.log(`Card Loader displaying: ${qualified_id.courseID}::${qualified_id.cardID}`);\n\n this.loading = true;\n const _courseID = qualified_id.courseID;\n const _cardID = qualified_id.cardID;\n const courseDB = getDataLayer().getCourseDB(_courseID);\n\n try {\n const tmpCardData = (await courseDB.getCourseDoc(_cardID)) as CardData;\n const tmpView = this.viewLookup(tmpCardData.id_view);\n const tmpDataDocs = tmpCardData.id_displayable_data.map((id) => {\n return courseDB.getCourseDoc(id, {\n attachments: true,\n binary: true,\n });\n });\n\n const tmpData = [];\n\n for (const docPromise of tmpDataDocs) {\n const doc = (await docPromise) as DisplayableData;\n tmpData.unshift(displayableDataToViewData(doc));\n }\n\n this.data = tmpData;\n this.view = markRaw(tmpView as ViewComponent);\n this.cardID = _cardID;\n this.courseID = _courseID;\n } catch (e) {\n throw new Error(`[CardLoader] Error loading card: ${JSON.stringify(e)}, ${e}`);\n } finally {\n this.loading = false;\n this.$emit('card-loaded');\n }\n },\n },\n});\n</script>\n\n<style scoped>\n.cardView {\n padding: 15px;\n border-radius: 8px;\n}\n\n.component-fade-enter-active,\n.component-fade-leave-active {\n transition: opacity 0.3s ease;\n}\n.component-fade-enter, .component-fade-leave-to\n/* .component-fade-leave-active below version 2.1.8 */ {\n opacity: 0;\n}\n</style>\n"],"mappings":";;;;;;AA6BA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,YAAY,EACV,YAAA,GACD;CAED,OAAO;EACL,cAAc;GACZ,MAAM;GACN,UAAU;GACV,SAAS;GACV;EACD,cAAc;GACZ,MAAM;GACN,UAAU;GACX;EACD,YAAY;GACV,MAAM;GACN,UAAU;GACX;EACF;CAED,OAAO;AACL,SAAO;GACL,SAAS;GACT,MAAM;GACN,MAAM,EAAC;GACP,UAAU;GACV,QAAQ;GACT;;CAGH,UAAU;AACR,OAAK,UAAU;;CAGjB,OAAO,EACL,cAAc;EACZ,WAAW;EACX,UAAU;AACR,QAAK,UAAU;;EAElB,EACF;CAED,SAAS;EACP,gBAAgB,GAAe;AAK7B,GAJA,EAAI;gCACsB,EAAE,UAAS;qBACtB,EAAE,UAAS;QACxB,EACF,KAAK,MAAM,gBAAgB,EAAE;;EAG/B,MAAM,WAAW;GACf,IAAM,IAAe,KAAK;AAG1B,GAFA,QAAQ,IAAI,2BAA2B,EAAa,SAAS,IAAI,EAAa,SAAS,EAEvF,KAAK,UAAU;GACf,IAAM,IAAY,EAAa,UACzB,IAAU,EAAa,QACvB,IAAW,GAAc,CAAC,YAAY,EAAU;AAEtD,OAAI;IACF,IAAM,IAAe,MAAM,EAAS,aAAa,EAAQ,EACnD,IAAU,KAAK,WAAW,EAAY,QAAQ,EAC9C,IAAc,EAAY,oBAAoB,KAAK,MAChD,EAAS,aAAa,GAAI;KAC/B,aAAa;KACb,QAAQ;KACT,CAAC,CACF,EAEI,IAAU,EAAE;AAElB,SAAK,IAAM,KAAc,GAAa;KACpC,IAAM,IAAO,MAAM;AACnB,OAAQ,QAAQ,EAA0B,EAAI,CAAC;;AAMjD,IAHA,KAAK,OAAO,GACZ,KAAK,OAAO,EAAQ,EAAyB,EAC7C,KAAK,SAAS,GACd,KAAK,WAAW;YACT,GAAG;AACV,UAAU,MAAM,oCAAoC,KAAK,UAAU,EAAE,CAAC,IAAI,IAAI;aACtE;AAER,IADA,KAAK,UAAU,IACf,KAAK,MAAM,cAAc;;;EAG9B;CACF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
3
+ import t from "./CardViewer.vue_vue_type_script_lang.mjs";
4
+ /* empty css */
5
+ import { createBlock as n, openBlock as r, resolveComponent as i, resolveDynamicComponent as a, withCtx as o } from "vue";
6
+ //#region src/components/cardRendering/CardViewer.vue
7
+ function _sfc_render(e, t, s, c, l, u) {
8
+ let d = i("v-card");
9
+ return e.frameless ? (r(), n(a(e.view), {
10
+ ref: "activeView",
11
+ key: e.course_id + "-" + e.card_id + "-" + e.sessionOrder,
12
+ data: e.data,
13
+ "modify-difficulty": e.user_elo.global.score - e.card_elo,
14
+ class: "cardView",
15
+ onEmitResponse: t[0] || (t[0] = (t) => e.processResponse(t)),
16
+ onRequestReplan: t[1] || (t[1] = (t) => e.$emit("requestReplan", t)),
17
+ onReadyToAdvance: t[2] || (t[2] = (t) => e.$emit("readyToAdvance"))
18
+ }, null, 40, ["data", "modify-difficulty"])) : (r(), n(d, {
19
+ key: 1,
20
+ elevation: "12"
21
+ }, {
22
+ default: o(() => [(r(), n(a(e.view), {
23
+ ref: "activeView",
24
+ key: e.course_id + "-" + e.card_id + "-" + e.sessionOrder,
25
+ data: e.data,
26
+ "modify-difficulty": e.user_elo.global.score - e.card_elo,
27
+ class: "cardView ma-2 pa-2",
28
+ onEmitResponse: t[3] || (t[3] = (t) => e.processResponse(t)),
29
+ onRequestReplan: t[4] || (t[4] = (t) => e.$emit("requestReplan", t)),
30
+ onReadyToAdvance: t[5] || (t[5] = (t) => e.$emit("readyToAdvance"))
31
+ }, null, 40, ["data", "modify-difficulty"]))]),
32
+ _: 1
33
+ }));
34
+ }
35
+ var s = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-2d892b82"]]);
36
+ //#endregion
37
+ export { s as default };
38
+
39
+ //# sourceMappingURL=CardViewer.mjs.map