@vue-skuilder/common-ui 0.2.35 → 0.2.37
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/_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs +13 -0
- package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPrimitive.mjs +15 -0
- package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPropertyKey.mjs +10 -0
- package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/typeof.mjs +12 -0
- package/dist/_virtual/_plugin-vue_export-helper.mjs +9 -0
- package/dist/_virtual/_rolldown/runtime.mjs +7 -0
- package/dist/admin/common-ui-admin.es.js +259 -23774
- package/dist/admin/common-ui-admin.es.js.map +1 -1
- package/dist/assets/index.css +2 -1
- package/dist/components/CardBrowser.mjs +63 -0
- package/dist/components/CardBrowser.mjs.map +1 -0
- package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs +50 -0
- package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CardHistoryViewer.mjs +70 -0
- package/dist/components/CardHistoryViewer.mjs.map +1 -0
- package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs +108 -0
- package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CardSearch.mjs +26 -0
- package/dist/components/CardSearch.mjs.map +1 -0
- package/dist/components/CardSearch.vue_vue_type_script_lang.mjs +17 -0
- package/dist/components/CardSearch.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CardSearchResults.mjs +32 -0
- package/dist/components/CardSearchResults.mjs.map +1 -0
- package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs +71 -0
- package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CourseCardBrowser.mjs +175 -0
- package/dist/components/CourseCardBrowser.mjs.map +1 -0
- package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs +173 -0
- package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CourseInformation.mjs +132 -0
- package/dist/components/CourseInformation.mjs.map +1 -0
- package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs +56 -0
- package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/CourseTagFilterWidget.mjs +114 -0
- package/dist/components/CourseTagFilterWidget.mjs.map +1 -0
- package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs +65 -0
- package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/HeatMap.mjs +40 -0
- package/dist/components/HeatMap.mjs.map +1 -0
- package/dist/components/HeatMap.vue_vue_type_script_lang.mjs +211 -0
- package/dist/components/HeatMap.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/PaginatingToolbar.mjs +94 -0
- package/dist/components/PaginatingToolbar.mjs.map +1 -0
- package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs +36 -0
- package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SessionControllerDebug.mjs +130 -0
- package/dist/components/SessionControllerDebug.mjs.map +1 -0
- package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs +45 -0
- package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SkMouseTrap.mjs +66 -0
- package/dist/components/SkMouseTrap.mjs.map +1 -0
- package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs +31 -0
- package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SkMouseTrapToolTip.mjs +28 -0
- package/dist/components/SkMouseTrapToolTip.mjs.map +1 -0
- package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs +91 -0
- package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SnackbarService.mjs +24 -0
- package/dist/components/SnackbarService.mjs.map +1 -0
- package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs +34 -0
- package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/SnackbarService2.mjs +40 -0
- package/dist/components/SnackbarService2.mjs.map +1 -0
- package/dist/components/StudySession.mjs +123 -0
- package/dist/components/StudySession.mjs.map +1 -0
- package/dist/components/StudySession.vue_vue_type_script_lang.mjs +280 -0
- package/dist/components/StudySession.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/StudySessionTimer.mjs +50 -0
- package/dist/components/StudySessionTimer.mjs.map +1 -0
- package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs +43 -0
- package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/TagsInput.mjs +45 -0
- package/dist/components/TagsInput.mjs.map +1 -0
- package/dist/components/TagsInput.vue_vue_type_script_lang.mjs +117 -0
- package/dist/components/TagsInput.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/UserTagPreferences.mjs +205 -0
- package/dist/components/UserTagPreferences.mjs.map +1 -0
- package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs +139 -0
- package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/RequestPasswordReset.mjs +96 -0
- package/dist/components/auth/RequestPasswordReset.mjs.map +1 -0
- package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs +47 -0
- package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/ResetPassword.mjs +129 -0
- package/dist/components/auth/ResetPassword.mjs.map +1 -0
- package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs +69 -0
- package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/UserChip.mjs +9 -0
- package/dist/components/auth/UserChip.mjs.map +1 -0
- package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs +213 -0
- package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/auth/UserLogin.mjs +9 -0
- package/dist/components/auth/UserLogin.mjs.map +1 -0
- package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs +155 -0
- package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.mjs +9 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.mjs.map +1 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs +126 -0
- package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/auth/UserRegistration.mjs +147 -0
- package/dist/components/auth/UserRegistration.mjs.map +1 -0
- package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs +130 -0
- package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/auth/VerifyEmail.mjs +118 -0
- package/dist/components/auth/VerifyEmail.mjs.map +1 -0
- package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs +59 -0
- package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/AudioAutoPlayer.mjs +9 -0
- package/dist/components/cardRendering/AudioAutoPlayer.mjs.map +1 -0
- package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs +69 -0
- package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/cardRendering/CardLoader.mjs +31 -0
- package/dist/components/cardRendering/CardLoader.mjs.map +1 -0
- package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs +75 -0
- package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/CardViewer.mjs +39 -0
- package/dist/components/cardRendering/CardViewer.mjs.map +1 -0
- package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs +66 -0
- package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/CodeBlockRenderer.mjs +8 -0
- package/dist/components/cardRendering/CodeBlockRenderer.mjs.map +1 -0
- package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs +44 -0
- package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/cardRendering/MarkdownRenderer.mjs +21 -0
- package/dist/components/cardRendering/MarkdownRenderer.mjs.map +1 -0
- package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs +24 -0
- package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/cardRendering/MarkdownRendererHelpers.mjs +79 -0
- package/dist/components/cardRendering/MarkdownRendererHelpers.mjs.map +1 -0
- package/dist/components/cardRendering/MdTokenRenderer.mjs +9 -0
- package/dist/components/cardRendering/MdTokenRenderer.mjs.map +1 -0
- package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs +176 -0
- package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/components/studentInputs/BaseUserInput.mjs +54 -0
- package/dist/components/studentInputs/BaseUserInput.mjs.map +1 -0
- package/dist/components/studentInputs/MultipleChoiceOption.mjs +26 -0
- package/dist/components/studentInputs/MultipleChoiceOption.mjs.map +1 -0
- package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs +76 -0
- package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/RadioMultipleChoice.mjs +33 -0
- package/dist/components/studentInputs/RadioMultipleChoice.mjs.map +1 -0
- package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs +105 -0
- package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/TrueFalse.mjs +19 -0
- package/dist/components/studentInputs/TrueFalse.mjs.map +1 -0
- package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs +21 -0
- package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputNumber.mjs +33 -0
- package/dist/components/studentInputs/UserInputNumber.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs +25 -0
- package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputString.mjs +22 -0
- package/dist/components/studentInputs/UserInputString.mjs.map +1 -0
- package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs +23 -0
- package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/components/studentInputs/fillInInput.mjs +25 -0
- package/dist/components/studentInputs/fillInInput.mjs.map +1 -0
- package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs +26 -0
- package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs.map +1 -0
- package/dist/composables/CompositionViewable.mjs +65 -0
- package/dist/composables/CompositionViewable.mjs.map +1 -0
- package/dist/composables/Displayable.mjs +36 -0
- package/dist/composables/Displayable.mjs.map +1 -0
- package/dist/composables/useAuthUI.mjs +38 -0
- package/dist/composables/useAuthUI.mjs.map +1 -0
- package/dist/composables/useEntitlements.mjs +58 -0
- package/dist/composables/useEntitlements.mjs.map +1 -0
- package/dist/index.mjs +49 -0
- package/dist/plugins/pinia.mjs +12 -0
- package/dist/plugins/pinia.mjs.map +1 -0
- package/dist/services/authAPI.mjs +159 -0
- package/dist/services/authAPI.mjs.map +1 -0
- package/dist/stores/useAuthStore.mjs +68 -0
- package/dist/stores/useAuthStore.mjs.map +1 -0
- package/dist/stores/useCardPreviewModeStore.mjs +20 -0
- package/dist/stores/useCardPreviewModeStore.mjs.map +1 -0
- package/dist/stores/useConfigStore.mjs +60 -0
- package/dist/stores/useConfigStore.mjs.map +1 -0
- package/dist/utils/SkldrMouseTrap.mjs +48 -0
- package/dist/utils/SkldrMouseTrap.mjs.map +1 -0
- package/dist/utils/passwordValidation.mjs +12 -0
- package/dist/utils/passwordValidation.mjs.map +1 -0
- package/package.json +7 -8
- package/dist/MarkdownRenderer-U_iPiA2x.mjs +0 -4966
- package/dist/MarkdownRenderer-U_iPiA2x.mjs.map +0 -1
- package/dist/assets/MarkdownRenderer.css +0 -1
- package/dist/common-ui.es.js +0 -5090
- package/dist/common-ui.es.js.map +0 -1
- package/dist/common-ui.umd.js +0 -77
- package/dist/common-ui.umd.js.map +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import "../../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
3
|
+
import t from "./UserInputNumber.vue_vue_type_script_lang.mjs";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import { createBlock as n, createVNode as r, openBlock as i, resolveComponent as a, withCtx as o, withKeys as s } from "vue";
|
|
6
|
+
//#region src/components/studentInputs/UserInputNumber.vue
|
|
7
|
+
function _sfc_render(e, t, c, l, u, d) {
|
|
8
|
+
let f = a("v-text-field"), p = a("v-container");
|
|
9
|
+
return i(), n(p, { class: "pa-0" }, {
|
|
10
|
+
default: o(() => [r(f, {
|
|
11
|
+
ref: "input",
|
|
12
|
+
modelValue: e.answer,
|
|
13
|
+
"onUpdate:modelValue": t[0] || (t[0] = (t) => e.answer = t),
|
|
14
|
+
"prepend-icon": "edit",
|
|
15
|
+
autofocus: e.autofocus,
|
|
16
|
+
"row-height": "24",
|
|
17
|
+
"toggle-keys": "[13,32]",
|
|
18
|
+
class: "text-h5",
|
|
19
|
+
rules: [e.isNumeric],
|
|
20
|
+
onKeyup: t[1] || (t[1] = s((t) => e.submitAnswer(e.makeNumeric(e.answer)), ["enter"]))
|
|
21
|
+
}, null, 8, [
|
|
22
|
+
"modelValue",
|
|
23
|
+
"autofocus",
|
|
24
|
+
"rules"
|
|
25
|
+
])]),
|
|
26
|
+
_: 1
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
var c = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-a56dcd1c"]]);
|
|
30
|
+
//#endregion
|
|
31
|
+
export { c as default };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=UserInputNumber.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserInputNumber.mjs","names":[],"sources":["../../../src/components/studentInputs/UserInputNumber.vue"],"sourcesContent":["<template>\n <v-container class=\"pa-0\">\n <v-text-field\n ref=\"input\"\n v-model=\"answer\"\n prepend-icon=\"edit\"\n :autofocus=\"autofocus\"\n row-height=\"24\"\n toggle-keys=\"[13,32]\"\n class=\"text-h5\"\n :rules=\"[isNumeric]\"\n @keyup.enter=\"submitAnswer(makeNumeric(answer))\"\n ></v-text-field>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { Answer } from '@vue-skuilder/common';\nimport UserInput from './BaseUserInput';\nimport { defineComponent } from 'vue';\n\ntype InputNumberRefs = {\n input: HTMLInputElement;\n};\n\ntype InputNumberInstance = ReturnType<typeof defineComponent> & {\n $refs: InputNumberRefs;\n};\n\nexport default defineComponent({\n name: 'UserInputNumber',\n\n ref: {} as InputNumberRefs,\n\n extends: UserInput,\n\n methods: {\n mounted(this: InputNumberInstance) {\n this.$refs.input.focus();\n },\n\n isNumeric(s: string): boolean {\n return !isNaN(Number.parseFloat(s));\n },\n\n makeNumeric(num: Answer): number {\n if (typeof num === 'string') {\n return Number.parseFloat(num);\n } else {\n throw new Error('Expected a string, got ' + typeof num);\n }\n },\n },\n});\n</script>\n\n<style scoped>\n.userInput {\n border: none;\n text-align: center;\n border-bottom: 1px black;\n}\n</style>\n"],"mappings":";;;;;;;;aACE,EAYc,GAAA,EAZD,OAAM,QAAM,EAAA;EAD3B,SAAA,QAYoB,CAVhB,EAUgB,GAAA;GATd,KAAI;GAHV,YAIe,EAAA;GAJf,uBAAA,EAAA,OAAA,EAAA,MAAA,MAAA,EAIe,SAAM;GACf,gBAAa;GACZ,WAAW,EAAA;GACZ,cAAW;GACX,eAAY;GACZ,OAAM;GACL,OAAK,CAAG,EAAA,UAAS;GACjB,SAAK,EAAA,OAAA,EAAA,KAXZ,GAAA,MAWoB,EAAA,aAAa,EAAA,YAAY,EAAA,OAAM,CAAA,EAAA,CAAA,QAAA,CAAA;;;;;;EAXnD,GAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "../../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "./BaseUserInput.mjs";
|
|
3
|
+
import { defineComponent as t } from "vue";
|
|
4
|
+
//#region src/components/studentInputs/UserInputNumber.vue?vue&type=script&lang.ts
|
|
5
|
+
var n = t({
|
|
6
|
+
name: "UserInputNumber",
|
|
7
|
+
ref: {},
|
|
8
|
+
extends: e,
|
|
9
|
+
methods: {
|
|
10
|
+
mounted() {
|
|
11
|
+
this.$refs.input.focus();
|
|
12
|
+
},
|
|
13
|
+
isNumeric(e) {
|
|
14
|
+
return !isNaN(Number.parseFloat(e));
|
|
15
|
+
},
|
|
16
|
+
makeNumeric(e) {
|
|
17
|
+
if (typeof e == "string") return Number.parseFloat(e);
|
|
18
|
+
throw Error("Expected a string, got " + typeof e);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
//#endregion
|
|
23
|
+
export { n as default };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=UserInputNumber.vue_vue_type_script_lang.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserInputNumber.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/studentInputs/UserInputNumber.vue"],"sourcesContent":["<template>\n <v-container class=\"pa-0\">\n <v-text-field\n ref=\"input\"\n v-model=\"answer\"\n prepend-icon=\"edit\"\n :autofocus=\"autofocus\"\n row-height=\"24\"\n toggle-keys=\"[13,32]\"\n class=\"text-h5\"\n :rules=\"[isNumeric]\"\n @keyup.enter=\"submitAnswer(makeNumeric(answer))\"\n ></v-text-field>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { Answer } from '@vue-skuilder/common';\nimport UserInput from './BaseUserInput';\nimport { defineComponent } from 'vue';\n\ntype InputNumberRefs = {\n input: HTMLInputElement;\n};\n\ntype InputNumberInstance = ReturnType<typeof defineComponent> & {\n $refs: InputNumberRefs;\n};\n\nexport default defineComponent({\n name: 'UserInputNumber',\n\n ref: {} as InputNumberRefs,\n\n extends: UserInput,\n\n methods: {\n mounted(this: InputNumberInstance) {\n this.$refs.input.focus();\n },\n\n isNumeric(s: string): boolean {\n return !isNaN(Number.parseFloat(s));\n },\n\n makeNumeric(num: Answer): number {\n if (typeof num === 'string') {\n return Number.parseFloat(num);\n } else {\n throw new Error('Expected a string, got ' + typeof num);\n }\n },\n },\n});\n</script>\n\n<style scoped>\n.userInput {\n border: none;\n text-align: center;\n border-bottom: 1px black;\n}\n</style>\n"],"mappings":";;;;AA6BA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,KAAK,EAAC;CAEN,SAAS;CAET,SAAS;EACP,UAAmC;AACjC,QAAK,MAAM,MAAM,OAAO;;EAG1B,UAAU,GAAoB;AAC5B,UAAO,CAAC,MAAM,OAAO,WAAW,EAAE,CAAC;;EAGrC,YAAY,GAAqB;AAC/B,OAAI,OAAO,KAAQ,SACjB,QAAO,OAAO,WAAW,EAAI;AAE7B,SAAU,MAAM,4BAA4B,OAAO,EAAI;;EAG5D;CACF,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "../../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
3
|
+
import t from "./UserInputString.vue_vue_type_script_lang.mjs";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import { createElementBlock as n, createElementVNode as r, openBlock as i, vModelText as a, withDirectives as o, withKeys as s } from "vue";
|
|
6
|
+
//#region src/components/studentInputs/UserInputString.vue
|
|
7
|
+
var c = { class: "user-input-container" }, l = ["autofocus"];
|
|
8
|
+
function _sfc_render(e, t, u, d, f, p) {
|
|
9
|
+
return i(), n("span", c, [o(r("input", {
|
|
10
|
+
"onUpdate:modelValue": t[0] || (t[0] = (t) => e.answer = t),
|
|
11
|
+
autofocus: e.autofocus,
|
|
12
|
+
type: "text",
|
|
13
|
+
class: "user-input-string",
|
|
14
|
+
ref: "input",
|
|
15
|
+
onKeyup: t[1] || (t[1] = s((t) => e.submitAnswer(e.answer), ["enter"]))
|
|
16
|
+
}, null, 40, l), [[a, e.answer]])]);
|
|
17
|
+
}
|
|
18
|
+
var u = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-aa14961f"]]);
|
|
19
|
+
//#endregion
|
|
20
|
+
export { u as default };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=UserInputString.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserInputString.mjs","names":[],"sources":["../../../src/components/studentInputs/UserInputString.vue"],"sourcesContent":["<template>\n <span class=\"user-input-container\">\n <input\n v-model=\"answer\"\n :autofocus=\"autofocus\"\n type=\"text\"\n class=\"user-input-string\"\n ref=\"input\"\n @keyup.enter=\"submitAnswer(answer)\"\n />\n </span>\n</template>\n\n<script lang=\"ts\">\n// @compositionstart=\"onCompositionStart\"\n// @compositionend=\"onCompositionEnd\"\nimport UserInput from './BaseUserInput';\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'UserInputString',\n extends: UserInput,\n\n props: {\n icon: {\n type: Boolean,\n required: false,\n },\n },\n\n computed: {\n prependIcon(): string {\n return this.icon ? 'edit' : '';\n },\n },\n\n mounted() {\n (this.$refs.input as HTMLInputElement)?.focus();\n },\n\n methods: {\n // debugInput(e: Event) {\n // const target = e.target as HTMLInputElement;\n // console.log('Input event:', {\n // value: target.value,\n // currentAnswer: this.answer,\n // target,\n // });\n // },\n // debugKeyup(e: KeyboardEvent) {\n // const target = e.target as HTMLInputElement;\n // console.log('Keyup event:', {\n // key: e.key,\n // value: target.value,\n // currentAnswer: this.answer,\n // target,\n // });\n // },\n },\n});\n</script>\n\n<style scoped>\n.user-input-container {\n display: inline-block;\n min-width: 6em;\n vertical-align: baseline;\n}\n\n.user-input-string {\n display: inline-block;\n background: transparent;\n border: none;\n border-bottom: 1px solid currentColor;\n color: currentColor;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n padding: 0;\n margin: 0;\n text-align: center;\n width: 100%;\n outline: none;\n}\n\n.user-input-string:focus {\n border-bottom: 2px solid currentColor;\n}\n</style>\n"],"mappings":";;;;;;UACQ,OAAM,wBAAsB,MADpC,CAAA,YAAA;;aACE,EASO,QATP,GASO,CAAA,EARL,EAOE,SAAA;EATN,uBAAA,EAAA,OAAA,EAAA,MAAA,MAAA,EAGe,SAAM;EACd,WAAW,EAAA;EACZ,MAAK;EACL,OAAM;EACN,KAAI;EACH,SAAK,EAAA,OAAA,EAAA,KARZ,GAAA,MAQoB,EAAA,aAAa,EAAA,OAAM,EAAA,CAAA,QAAA,CAAA;cARvC,EAAA,EAAA,CAAA,CAAA,GAGe,EAAA,OAAM,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import "../../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "./BaseUserInput.mjs";
|
|
3
|
+
import { defineComponent as t } from "vue";
|
|
4
|
+
//#region src/components/studentInputs/UserInputString.vue?vue&type=script&lang.ts
|
|
5
|
+
var n = t({
|
|
6
|
+
name: "UserInputString",
|
|
7
|
+
extends: e,
|
|
8
|
+
props: { icon: {
|
|
9
|
+
type: Boolean,
|
|
10
|
+
required: !1
|
|
11
|
+
} },
|
|
12
|
+
computed: { prependIcon() {
|
|
13
|
+
return this.icon ? "edit" : "";
|
|
14
|
+
} },
|
|
15
|
+
mounted() {
|
|
16
|
+
this.$refs.input?.focus();
|
|
17
|
+
},
|
|
18
|
+
methods: {}
|
|
19
|
+
});
|
|
20
|
+
//#endregion
|
|
21
|
+
export { n as default };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=UserInputString.vue_vue_type_script_lang.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserInputString.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/studentInputs/UserInputString.vue"],"sourcesContent":["<template>\n <span class=\"user-input-container\">\n <input\n v-model=\"answer\"\n :autofocus=\"autofocus\"\n type=\"text\"\n class=\"user-input-string\"\n ref=\"input\"\n @keyup.enter=\"submitAnswer(answer)\"\n />\n </span>\n</template>\n\n<script lang=\"ts\">\n// @compositionstart=\"onCompositionStart\"\n// @compositionend=\"onCompositionEnd\"\nimport UserInput from './BaseUserInput';\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'UserInputString',\n extends: UserInput,\n\n props: {\n icon: {\n type: Boolean,\n required: false,\n },\n },\n\n computed: {\n prependIcon(): string {\n return this.icon ? 'edit' : '';\n },\n },\n\n mounted() {\n (this.$refs.input as HTMLInputElement)?.focus();\n },\n\n methods: {\n // debugInput(e: Event) {\n // const target = e.target as HTMLInputElement;\n // console.log('Input event:', {\n // value: target.value,\n // currentAnswer: this.answer,\n // target,\n // });\n // },\n // debugKeyup(e: KeyboardEvent) {\n // const target = e.target as HTMLInputElement;\n // console.log('Keyup event:', {\n // key: e.key,\n // value: target.value,\n // currentAnswer: this.answer,\n // target,\n // });\n // },\n },\n});\n</script>\n\n<style scoped>\n.user-input-container {\n display: inline-block;\n min-width: 6em;\n vertical-align: baseline;\n}\n\n.user-input-string {\n display: inline-block;\n background: transparent;\n border: none;\n border-bottom: 1px solid currentColor;\n color: currentColor;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n padding: 0;\n margin: 0;\n text-align: center;\n width: 100%;\n outline: none;\n}\n\n.user-input-string:focus {\n border-bottom: 2px solid currentColor;\n}\n</style>\n"],"mappings":";;;;AAmBA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CACN,SAAS;CAET,OAAO,EACL,MAAM;EACJ,MAAM;EACN,UAAU;EACX,EACF;CAED,UAAU,EACR,cAAsB;AACpB,SAAO,KAAK,OAAO,SAAS;IAE/B;CAED,UAAU;AACP,OAAK,MAAM,OAA4B,OAAO;;CAGjD,SAAS,EAkBR;CACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "../../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
3
|
+
import t from "./fillInInput.vue_vue_type_script_lang.mjs";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import { createBlock as n, createElementBlock as r, openBlock as i, resolveComponent as a } from "vue";
|
|
6
|
+
//#region src/components/studentInputs/fillInInput.vue
|
|
7
|
+
var o = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "text-h5 underline"
|
|
10
|
+
};
|
|
11
|
+
function _sfc_render(e, t, s, c, l, u) {
|
|
12
|
+
let d = a("user-input-string");
|
|
13
|
+
return e.radioType ? (i(), r("span", o, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0")) : (i(), n(d, {
|
|
14
|
+
key: 1,
|
|
15
|
+
id: "input",
|
|
16
|
+
icon: !1,
|
|
17
|
+
type: "text",
|
|
18
|
+
value: e.processedText
|
|
19
|
+
}, null, 8, ["value"]));
|
|
20
|
+
}
|
|
21
|
+
var s = /* @__PURE__ */ e(t, [["render", _sfc_render], ["__scopeId", "data-v-486ac035"]]);
|
|
22
|
+
//#endregion
|
|
23
|
+
export { s as default };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=fillInInput.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fillInInput.mjs","names":[],"sources":["../../../src/components/studentInputs/fillInInput.vue"],"sourcesContent":["<template>\n <span v-if=\"radioType\" class=\"text-h5 underline\"\n > </span\n >\n <user-input-string v-else id=\"input\" :icon=\"false\" type=\"text\" :value=\"processedText\" />\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, ref, computed, onMounted } from 'vue';\nimport UserInputString from './UserInputString.vue';\n\nexport default defineComponent({\n name: 'FillInInput',\n\n components: {\n UserInputString,\n },\n\n props: {\n text: {\n type: String,\n required: true,\n },\n },\n\n setup(props) {\n // State\n const inputType = ref<'text' | 'radio'>('text');\n const processedText = ref('');\n\n // Computed\n const radioType = computed(() => {\n return props.text.split('||').length > 1;\n });\n\n // Process text on mount\n onMounted(() => {\n console.log(`fillinCreated w/ text: ${props.text}`);\n\n // Remove mustache syntax\n processedText.value = props.text.substring(2, props.text.length - 2);\n\n console.log(`fillin text trimmed to: ${processedText.value}`);\n\n const split = processedText.value.split('||');\n if (split.length > 1) {\n inputType.value = 'radio';\n }\n });\n\n return {\n inputType,\n radioType,\n processedText,\n };\n },\n});\n</script>\n\n<style scoped>\n#input {\n display: inline-block;\n min-width: 4em;\n text-align: center;\n}\n\n.underline {\n text-decoration: underline;\n text-decoration-style: solid 14px;\n}\n</style>\n"],"mappings":";;;;;;;CAAA,KAAA;CACyB,OAAM;;;;QAAjB,EAAA,aAAA,GAAA,EAAZ,EAEC,QAFD,GACG,uDAA8E,KAAA,GAAA,EAEjF,EAAwF,GAAA;EAJ1F,KAAA;EAI4B,IAAG;EAAS,MAAM;EAAO,MAAK;EAAQ,OAAO,EAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "../../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import e from "./UserInputString.mjs";
|
|
3
|
+
import { computed as t, defineComponent as n, onMounted as r, ref as i } from "vue";
|
|
4
|
+
//#region src/components/studentInputs/fillInInput.vue?vue&type=script&lang.ts
|
|
5
|
+
var a = n({
|
|
6
|
+
name: "FillInInput",
|
|
7
|
+
components: { UserInputString: e },
|
|
8
|
+
props: { text: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: !0
|
|
11
|
+
} },
|
|
12
|
+
setup(e) {
|
|
13
|
+
let n = i("text"), a = i(""), o = t(() => e.text.split("||").length > 1);
|
|
14
|
+
return r(() => {
|
|
15
|
+
console.log(`fillinCreated w/ text: ${e.text}`), a.value = e.text.substring(2, e.text.length - 2), console.log(`fillin text trimmed to: ${a.value}`), a.value.split("||").length > 1 && (n.value = "radio");
|
|
16
|
+
}), {
|
|
17
|
+
inputType: n,
|
|
18
|
+
radioType: o,
|
|
19
|
+
processedText: a
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
//#endregion
|
|
24
|
+
export { a as default };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=fillInInput.vue_vue_type_script_lang.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fillInInput.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/studentInputs/fillInInput.vue"],"sourcesContent":["<template>\n <span v-if=\"radioType\" class=\"text-h5 underline\"\n > </span\n >\n <user-input-string v-else id=\"input\" :icon=\"false\" type=\"text\" :value=\"processedText\" />\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, ref, computed, onMounted } from 'vue';\nimport UserInputString from './UserInputString.vue';\n\nexport default defineComponent({\n name: 'FillInInput',\n\n components: {\n UserInputString,\n },\n\n props: {\n text: {\n type: String,\n required: true,\n },\n },\n\n setup(props) {\n // State\n const inputType = ref<'text' | 'radio'>('text');\n const processedText = ref('');\n\n // Computed\n const radioType = computed(() => {\n return props.text.split('||').length > 1;\n });\n\n // Process text on mount\n onMounted(() => {\n console.log(`fillinCreated w/ text: ${props.text}`);\n\n // Remove mustache syntax\n processedText.value = props.text.substring(2, props.text.length - 2);\n\n console.log(`fillin text trimmed to: ${processedText.value}`);\n\n const split = processedText.value.split('||');\n if (split.length > 1) {\n inputType.value = 'radio';\n }\n });\n\n return {\n inputType,\n radioType,\n processedText,\n };\n },\n});\n</script>\n\n<style scoped>\n#input {\n display: inline-block;\n min-width: 4em;\n text-align: center;\n}\n\n.underline {\n text-decoration: underline;\n text-decoration-style: solid 14px;\n}\n</style>\n"],"mappings":";;;;AAWA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,YAAY,EACV,iBAAA,GACD;CAED,OAAO,EACL,MAAM;EACJ,MAAM;EACN,UAAU;EACX,EACF;CAED,MAAM,GAAO;EAEX,IAAM,IAAY,EAAsB,OAAO,EACzC,IAAgB,EAAI,GAAG,EAGvB,IAAY,QACT,EAAM,KAAK,MAAM,KAAK,CAAC,SAAS,EACvC;AAiBF,SAdA,QAAgB;AASd,GARA,QAAQ,IAAI,0BAA0B,EAAM,OAAO,EAGnD,EAAc,QAAQ,EAAM,KAAK,UAAU,GAAG,EAAM,KAAK,SAAS,EAAE,EAEpE,QAAQ,IAAI,2BAA2B,EAAc,QAAQ,EAE/C,EAAc,MAAM,MAAM,KAAK,CACnC,SAAS,MACjB,EAAU,QAAQ;IAEpB,EAEK;GACL;GACA;GACA;GACD;;CAEJ,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { customRef as e, ref as t } from "vue";
|
|
3
|
+
import n from "moment";
|
|
4
|
+
//#region src/composables/CompositionViewable.ts
|
|
5
|
+
function useViewable(r, i, a) {
|
|
6
|
+
let o = t(n.utc()), s = t([]), c = {
|
|
7
|
+
log: (e, ...t) => console.log(`[${a}]: `, e, ...t),
|
|
8
|
+
error: (e, ...t) => console.error(`[${a}]: `, e, ...t),
|
|
9
|
+
warn: (e, ...t) => console.warn(`[${a}]: `, e, ...t)
|
|
10
|
+
}, l = e(() => ({
|
|
11
|
+
get: () => Math.abs(n.utc().diff(o.value, "milliseconds")),
|
|
12
|
+
set: () => {}
|
|
13
|
+
})), getURL = (e, t = 0) => {
|
|
14
|
+
try {
|
|
15
|
+
if (r.data[t]?.[e]) return URL.createObjectURL(r.data[t][e]);
|
|
16
|
+
} catch (t) {
|
|
17
|
+
c.error("Error creating URL for item:", e, t);
|
|
18
|
+
}
|
|
19
|
+
return "";
|
|
20
|
+
}, emitResponse = (e) => {
|
|
21
|
+
i("emitResponse", e);
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
startTime: o,
|
|
25
|
+
hotKeys: s,
|
|
26
|
+
timeSpent: l,
|
|
27
|
+
logger: c,
|
|
28
|
+
getURL,
|
|
29
|
+
emitResponse
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function useQuestionView(e) {
|
|
33
|
+
let n = t(0), r = t(0), i = t([]), a = t(3), o = t(2), s = t(), submitAnswer = (t, n, a) => {
|
|
34
|
+
if (e.logger.log("submitAnswer called..."), !s.value) throw Error("Question not initialized");
|
|
35
|
+
i.value.push([t, n ?? ""]);
|
|
36
|
+
let o = e.timeSpent.value, c = s.value.evaluate(t, o);
|
|
37
|
+
e.logger.log(`evaluation of answer ${t}:`, c);
|
|
38
|
+
let l = {
|
|
39
|
+
...c,
|
|
40
|
+
priorAttemps: r.value,
|
|
41
|
+
courseID: "",
|
|
42
|
+
cardID: "",
|
|
43
|
+
timeSpent: o,
|
|
44
|
+
timeStamp: e.startTime.value,
|
|
45
|
+
userAnswer: t
|
|
46
|
+
};
|
|
47
|
+
return a?.deferAdvance !== void 0 && (l.deferAdvance = a.deferAdvance), c.isCorrect || r.value++, e.emitResponse(l), l;
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
priorSessionViews: n,
|
|
51
|
+
priorAttempts: r,
|
|
52
|
+
priorAnswers: i,
|
|
53
|
+
maxAttemptsPerView: a,
|
|
54
|
+
maxSessionViews: o,
|
|
55
|
+
question: s,
|
|
56
|
+
submitAnswer
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function isQuestionView(e) {
|
|
60
|
+
return typeof e == "object" && !!e && "submitAnswer" in e && "priorAttempts" in e;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { isQuestionView, useQuestionView, useViewable };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=CompositionViewable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositionViewable.mjs","names":[],"sources":["../../src/composables/CompositionViewable.ts"],"sourcesContent":["// src/base-course/CompositionViewable.ts\n\nimport moment from 'moment';\nimport { customRef, ref, Ref } from 'vue';\nimport { CardRecord, QuestionRecord } from '@vue-skuilder/db';\nimport { HotKey } from '../utils/SkldrMouseTrap';\nimport { Question } from './Displayable';\nimport { ViewData, Answer } from '@vue-skuilder/common';\n\n// Core interfaces to ensure type safety\nexport interface ViewableUtils {\n startTime: Ref<moment.Moment>;\n hotKeys: Ref<HotKey[]>;\n timeSpent: Readonly<Ref<number>>;\n logger: ViewableLogger;\n getURL: (item: string, dataShapeIndex?: number) => string;\n emitResponse: (record: CardRecord) => void;\n}\n\nexport interface ViewableLogger {\n log: (message?: unknown, ...params: unknown[]) => void;\n error: (message?: unknown, ...params: unknown[]) => void;\n warn: (message?: unknown, ...params: unknown[]) => void;\n}\n\n/**\n * Options that can be passed to `submitAnswer` to control framework behaviour.\n */\nexport interface SubmitAnswerOpts {\n /**\n * When true, the framework logs the card record and updates ELO/SRS but\n * does **not** advance to the next card. The view is expected to emit\n * `ready-to-advance` later to trigger navigation.\n */\n deferAdvance?: boolean;\n}\n\nexport interface QuestionViewUtils<Q extends Question> {\n priorSessionViews: Ref<number>;\n priorAttempts: Ref<number>;\n priorAnswers: Ref<[Answer, string][]>;\n maxAttemptsPerView: Ref<number>;\n maxSessionViews: Ref<number>;\n question: Ref<Q | undefined>;\n submitAnswer: (answer: Answer, submittingClass?: string, opts?: SubmitAnswerOpts) => QuestionRecord;\n}\n\n// Base composable for viewable functionality\nexport function useViewable(\n props: { data: ViewData[] },\n emit: (event: string, ...args: unknown[]) => void,\n componentName: string\n): ViewableUtils {\n const startTime = ref(moment.utc());\n const hotKeys = ref<HotKey[]>([]);\n\n const logger: ViewableLogger = {\n log: (message?: unknown, ...params: unknown[]) =>\n console.log(`[${componentName}]: `, message, ...params),\n error: (message?: unknown, ...params: unknown[]) =>\n console.error(`[${componentName}]: `, message, ...params),\n warn: (message?: unknown, ...params: unknown[]) =>\n console.warn(`[${componentName}]: `, message, ...params),\n };\n\n // Recomputed on every read. A computed caches its first read (moment.utc() isn't reactive),\n // so retries were recorded with the first attempt's time.\n const timeSpent = customRef<number>(() => ({\n get: () => Math.abs(moment.utc().diff(startTime.value, 'milliseconds')),\n set: () => {},\n }));\n\n const getURL = (item: string, dataShapeIndex = 0): string => {\n try {\n if (props.data[dataShapeIndex]?.[item]) {\n return URL.createObjectURL(props.data[dataShapeIndex][item] as Blob);\n }\n } catch (error) {\n logger.error('Error creating URL for item:', item, error);\n }\n return '';\n };\n\n const emitResponse = (record: CardRecord) => {\n emit('emitResponse', record);\n };\n\n return {\n startTime,\n hotKeys,\n timeSpent,\n logger,\n getURL,\n emitResponse,\n };\n}\n\n// Question view composable\nexport function useQuestionView<Q extends Question>(\n viewableUtils: ViewableUtils\n // modifyDifficulty?: number\n): QuestionViewUtils<Q> {\n const priorSessionViews = ref(0);\n const priorAttempts = ref(0);\n const priorAnswers = ref<[Answer, string][]>([]);\n const maxAttemptsPerView = ref(3);\n const maxSessionViews = ref(2);\n const question = ref<Q>();\n\n const submitAnswer = (answer: Answer, submittingClass?: string, opts?: SubmitAnswerOpts): QuestionRecord => {\n viewableUtils.logger.log('submitAnswer called...');\n\n if (!question.value) {\n throw new Error('Question not initialized');\n }\n\n priorAnswers.value.push([answer, submittingClass ?? '']);\n\n const timeSpent = viewableUtils.timeSpent.value;\n const evaluation = question.value.evaluate(answer, timeSpent);\n\n viewableUtils.logger.log(`evaluation of answer ${answer}:`, evaluation);\n\n const record: QuestionRecord = {\n ...evaluation,\n priorAttemps: priorAttempts.value,\n courseID: '',\n cardID: '',\n timeSpent,\n timeStamp: viewableUtils.startTime.value,\n userAnswer: answer,\n };\n\n // Merge deferAdvance from opts if provided (takes precedence over evaluate())\n if (opts?.deferAdvance !== undefined) {\n record.deferAdvance = opts.deferAdvance;\n }\n\n if (!evaluation.isCorrect) {\n priorAttempts.value++;\n }\n\n viewableUtils.emitResponse(record);\n return record;\n };\n\n return {\n priorSessionViews,\n priorAttempts,\n priorAnswers,\n maxAttemptsPerView,\n maxSessionViews,\n question,\n submitAnswer,\n };\n}\n\n// Helper functions\nexport function isQuestionView(component: unknown): component is QuestionViewUtils<Question> {\n return (\n typeof component === 'object' &&\n component !== null &&\n 'submitAnswer' in component &&\n 'priorAttempts' in component\n );\n}\n\n// Example usage in a child component:\n/*\nimport { defineComponent, PropType } from 'vue';\nimport { useViewable, useQuestionView } from './CompositionViewable';\nimport { MyCustomQuestion } from './types';\n\nexport default defineComponent({\n name: 'MyCustomQuestionView',\n props: {\n data: {\n type: Array as PropType<ViewData[]>,\n required: true,\n },\n modifyDifficulty: Number,\n },\n setup(props, { emit }) {\n const viewableUtils = useViewable(props, emit, 'MyCustomQuestionView');\n const questionUtils = useQuestionView<MyCustomQuestion>(viewableUtils, props.modifyDifficulty);\n\n // Initialize question\n questionUtils.question.value = new MyCustomQuestion(props.data);\n\n // Add custom logic here\n const customMethod = () => {\n viewableUtils.logger.log('Custom method called');\n // ...\n };\n\n return {\n ...viewableUtils,\n ...questionUtils,\n customMethod,\n };\n },\n template: `\n <div data-viewable=\"MyCustomQuestionView\">\n <!-- Your template here -->\n </div>\n `\n});\n*/\n"],"mappings":";;;;AAgDA,SAAgB,YACd,GACA,GACA,GACe;CACf,IAAM,IAAY,EAAI,EAAO,KAAK,CAAC,EAC7B,IAAU,EAAc,EAAE,CAAC,EAE3B,IAAyB;EAC7B,MAAM,GAAmB,GAAG,MAC1B,QAAQ,IAAI,IAAI,EAAc,MAAM,GAAS,GAAG,EAAO;EACzD,QAAQ,GAAmB,GAAG,MAC5B,QAAQ,MAAM,IAAI,EAAc,MAAM,GAAS,GAAG,EAAO;EAC3D,OAAO,GAAmB,GAAG,MAC3B,QAAQ,KAAK,IAAI,EAAc,MAAM,GAAS,GAAG,EAAO;EAC3D,EAIK,IAAY,SAAyB;EACzC,WAAW,KAAK,IAAI,EAAO,KAAK,CAAC,KAAK,EAAU,OAAO,eAAe,CAAC;EACvE,WAAW;EACZ,EAAE,EAEG,UAAU,GAAc,IAAiB,MAAc;AAC3D,MAAI;AACF,OAAI,EAAM,KAAK,KAAkB,GAC/B,QAAO,IAAI,gBAAgB,EAAM,KAAK,GAAgB,GAAc;WAE/D,GAAO;AACd,KAAO,MAAM,gCAAgC,GAAM,EAAM;;AAE3D,SAAO;IAGH,gBAAgB,MAAuB;AAC3C,IAAK,gBAAgB,EAAO;;AAG9B,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;;AAIH,SAAgB,gBACd,GAEsB;CACtB,IAAM,IAAoB,EAAI,EAAE,EAC1B,IAAgB,EAAI,EAAE,EACtB,IAAe,EAAwB,EAAE,CAAC,EAC1C,IAAqB,EAAI,EAAE,EAC3B,IAAkB,EAAI,EAAE,EACxB,IAAW,GAAQ,EAEnB,gBAAgB,GAAgB,GAA0B,MAA4C;AAG1G,MAFA,EAAc,OAAO,IAAI,yBAAyB,EAE9C,CAAC,EAAS,MACZ,OAAU,MAAM,2BAA2B;AAG7C,IAAa,MAAM,KAAK,CAAC,GAAQ,KAAmB,GAAG,CAAC;EAExD,IAAM,IAAY,EAAc,UAAU,OACpC,IAAa,EAAS,MAAM,SAAS,GAAQ,EAAU;AAE7D,IAAc,OAAO,IAAI,wBAAwB,EAAO,IAAI,EAAW;EAEvE,IAAM,IAAyB;GAC7B,GAAG;GACH,cAAc,EAAc;GAC5B,UAAU;GACV,QAAQ;GACR;GACA,WAAW,EAAc,UAAU;GACnC,YAAY;GACb;AAYD,SATI,GAAM,iBAAiB,KAAA,MACzB,EAAO,eAAe,EAAK,eAGxB,EAAW,aACd,EAAc,SAGhB,EAAc,aAAa,EAAO,EAC3B;;AAGT,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;AAIH,SAAgB,eAAe,GAA8D;AAC3F,QACE,OAAO,KAAc,cACrB,KACA,kBAAkB,KAClB,mBAAmB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { _defineProperty as e } from "../_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs";
|
|
3
|
+
import { FieldType as t } from "@vue-skuilder/common";
|
|
4
|
+
//#region src/composables/Displayable.ts
|
|
5
|
+
function isDefineComponent(e) {
|
|
6
|
+
return e.__isFragment !== void 0;
|
|
7
|
+
}
|
|
8
|
+
var Displayable = class {
|
|
9
|
+
constructor(e) {
|
|
10
|
+
if (e.length === 0) throw Error("\nDisplayable Constructor was called with no view Data.\n ");
|
|
11
|
+
validateData(this.dataShapes(), e);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
e(Displayable, "dataShapes", void 0), e(Displayable, "views", void 0), e(Displayable, "seedData", void 0), e(Displayable, "acceptsUserData", !0), e(Displayable, "seedMeta", void 0);
|
|
15
|
+
function validateData(e, n) {
|
|
16
|
+
for (let r = 0; r < e.length; r++) e[r].fields.forEach((e, i) => {
|
|
17
|
+
console.log(`[Displayable] shape[${r}].field[${i}]:\n ${JSON.stringify(e)}`), n[r][e.name] === void 0 && e.type !== t.MEDIA_UPLOADS && console.warn("[Displayable] missing data");
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
var Question = class extends Displayable {
|
|
21
|
+
displayedSkill(e, t) {
|
|
22
|
+
console.warn("Question is running the reference implementation of displayedSkill.\n Consider overriding!");
|
|
23
|
+
let n = 5e3, r = Math.min(t, 10 * n), i = r / n, a = r > n ? .8 ** i : 1, o = this.isCorrect(e) ? 1 : 0;
|
|
24
|
+
return o *= a, Math.min(o, 1);
|
|
25
|
+
}
|
|
26
|
+
evaluate(e, t) {
|
|
27
|
+
return {
|
|
28
|
+
isCorrect: this.isCorrect(e),
|
|
29
|
+
performance: this.displayedSkill(e, t)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { Displayable, Question, isDefineComponent };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=Displayable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Displayable.mjs","names":[],"sources":["../../src/composables/Displayable.ts"],"sourcesContent":["import { type DefineComponent, defineComponent } from 'vue';\nimport { FieldType, DataShape, ViewData, Answer, Evaluation, SeedMeta } from '@vue-skuilder/common';\n\n// [ ] #vue3 - post migration, specify this more precisely (no longer a hodge-podge)\nexport type ViewComponent =\n | DefineComponent<unknown, unknown, unknown>\n | ReturnType<typeof defineComponent>;\n\nexport function isDefineComponent(\n v: ViewComponent\n): v is DefineComponent<unknown, unknown, unknown> {\n return (v as DefineComponent<unknown, unknown, unknown>).__isFragment !== undefined;\n}\n\n// export function isComponentOptions(v: ViewComponent): v is ComponentOptions<any> {\n// return (v as ComponentOptions<Vue>).name !== undefined;\n// }\n\n// tslint:disable-next-line:max-classes-per-file\nexport abstract class Displayable {\n public static dataShapes: DataShape[];\n\n public static views: Array<ViewComponent>;\n public static seedData?: Array<unknown>;\n /**\n * True if this displayable content type is meant to have\n * user-submitted questions. False if supplied seedData array\n * is comprehensive for the content type. EG, a SingleDigitAddition\n * type may comprehensively supply 0+0,0+1,...,9+9 as its seed\n * data, and not want any user input.\n */\n public static acceptsUserData: boolean = true;\n\n /**\n * Optional tags and starting ELO for the cards seeded from one seedData\n * item. Without it, seeded cards start untagged at ~1000.\n */\n public static seedMeta?: (item: unknown) => SeedMeta;\n\n /**\n *\n */\n constructor(viewData: ViewData[]) {\n if (viewData.length === 0) {\n throw new Error(`\nDisplayable Constructor was called with no view Data.\n `);\n }\n validateData(this.dataShapes(), viewData);\n }\n\n public abstract dataShapes(): DataShape[];\n public abstract views(): Array<ViewComponent>;\n}\n\nfunction validateData(shape: DataShape[], data: ViewData[]) {\n for (let i = 0; i < shape.length; i++) {\n shape[i].fields.forEach((field, j) => {\n console.log(`[Displayable] shape[${i}].field[${j}]:\\n ${JSON.stringify(field)}`);\n if (data[i][field.name] === undefined && field.type !== FieldType.MEDIA_UPLOADS) {\n // throw new Error(`field validation failed:\\n\\t${field.name}, (${field.type})`);\n console.warn(`[Displayable] missing data`);\n }\n });\n }\n}\n\n// tslint:disable-next-line:max-classes-per-file\nexport abstract class Question extends Displayable {\n /**\n * returns a yes/no evaluation of a user's answer. Informs the SRS\n * algorithm's decision to expand or reset a card's spacing\n * @param answer\n */\n protected abstract isCorrect(answer: Answer): boolean;\n /**\n * returns a number from [0,1] representing the user's performance on the question,\n * which informs elo adjustments and SRS multipliers\n *\n * @param answer the user's answer\n * @param timeSpent the time the user spent on the card in milliseconds\n * @returns a rating of the user's displayed skill, from 0-1\n */\n protected displayedSkill(answer: Answer, timeSpent: number): number {\n console.warn(`Question is running the reference implementation of displayedSkill.\n Consider overriding!`);\n // experts should answer this question in <= 5 secnods (5000 ms)\n const expertSpeed = 5000;\n const userSpeed = Math.min(timeSpent, 10 * expertSpeed);\n\n // if userResponse is > 10 x expertSpeed, discount as probably afk / distracted ?\n\n const speedPenalty = userSpeed / expertSpeed;\n const speedPenaltyMultiplier = userSpeed > expertSpeed ? Math.pow(0.8, speedPenalty) : 1;\n\n let ret = this.isCorrect(answer) ? 1 : 0;\n\n ret = ret * speedPenaltyMultiplier;\n\n return Math.min(ret, 1);\n }\n\n /**\n *\n * @param answer the student's answer\n * @param timeSpent the amount of time spent in ms\n * @returns\n */\n public evaluate(answer: Answer, timeSpent: number): Evaluation {\n return {\n isCorrect: this.isCorrect(answer),\n performance: this.displayedSkill(answer, timeSpent),\n };\n }\n\n /*\n TODO:\n\n This class and its interface are critical in this app - it defines the app's\n methodology, or its architecture of methodologies, for making inferences based on\n student performance.\n\n Some future directions:\n\n displayedSkill() should receive contextual data as well as the direct report of\n a user's interaction with this card. Context includes, eg, the status of the current\n study session (is the user on tilt? have there been leading Qs? have there been distractors?),\n the status of the user's interaction with the card (new? mature? history of resets?)\n\n displayedSkill() should reach out to a course (or just the card, or card-type?) in order to receive\n custom skill-dimension evaluators. EG: a card in the ear training course tagged 'articulation'\n could trigger a fetch of a particular evaluator fcn for articulation. In general, we\n want high-dimension evaluations.\n\n answers should be processed for the likelihood of non-substantive-incorrectness. eg,\n 7 * 4 = 8 is much more likely to be a typo than a substantive error when compared\n with 7 * 4 = 21\n */\n}\n"],"mappings":";;;;AAQA,SAAgB,kBACd,GACiD;AACjD,QAAQ,EAAiD,iBAAiB,KAAA;;AAQ5E,IAAsB,cAAtB,MAAkC;CAuBhC,YAAY,GAAsB;AAChC,MAAI,EAAS,WAAW,EACtB,OAAU,MAAM,wEAER;AAEV,eAAa,KAAK,YAAY,EAAE,EAAS;;;eA5B7B,cAAA,KAAA,EAAA,iBAEA,SAAA,KAAA,EAAA,iBACA,YAAA,KAAA,EAAA,iBAQA,mBAA2B,GAAA,iBAM3B,YAAA,KAAA,EAAA;AAkBhB,SAAS,aAAa,GAAoB,GAAkB;AAC1D,MAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,IAChC,GAAM,GAAG,OAAO,SAAS,GAAO,MAAM;AAEpC,EADA,QAAQ,IAAI,uBAAuB,EAAE,UAAU,EAAE,OAAO,KAAK,UAAU,EAAM,GAAG,EAC5E,EAAK,GAAG,EAAM,UAAU,KAAA,KAAa,EAAM,SAAS,EAAU,iBAEhE,QAAQ,KAAK,6BAA6B;GAE5C;;AAKN,IAAsB,WAAtB,cAAuC,YAAY;CAejD,eAAyB,GAAgB,GAA2B;AAClE,UAAQ,KAAK,gGACS;EAEtB,IAAM,IAAc,KACd,IAAY,KAAK,IAAI,GAAW,KAAK,EAAY,EAIjD,IAAe,IAAY,GAC3B,IAAyB,IAAY,IAAuB,MAAK,IAAgB,GAEnF,IAAM,KAAK,UAAU,EAAO,GAAG,IAAI;AAIvC,SAFA,KAAY,GAEL,KAAK,IAAI,GAAK,EAAE;;CASzB,SAAgB,GAAgB,GAA+B;AAC7D,SAAO;GACL,WAAW,KAAK,UAAU,EAAO;GACjC,aAAa,KAAK,eAAe,GAAQ,EAAU;GACpD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { getCurrentUser as e } from "../stores/useAuthStore.mjs";
|
|
3
|
+
import { computed as t, ref as n } from "vue";
|
|
4
|
+
//#region src/composables/useAuthUI.ts
|
|
5
|
+
function useAuthUI() {
|
|
6
|
+
let r = n(!0), i = n(!1), a = n(!1), o = t(() => a.value ? {
|
|
7
|
+
showLoginRegistration: !1,
|
|
8
|
+
showLogout: !1,
|
|
9
|
+
showResetData: !0,
|
|
10
|
+
logoutLabel: "",
|
|
11
|
+
resetLabel: "Reset User Data"
|
|
12
|
+
} : {
|
|
13
|
+
showLoginRegistration: !0,
|
|
14
|
+
showLogout: !0,
|
|
15
|
+
showResetData: !1,
|
|
16
|
+
logoutLabel: "Log out",
|
|
17
|
+
resetLabel: ""
|
|
18
|
+
}), detectSyncStrategy = async () => {
|
|
19
|
+
try {
|
|
20
|
+
r.value = !0, a.value = !(await e()).syncStrategy?.canCreateAccount?.(), i.value = !0;
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.error("Failed to detect sync strategy:", e), a.value = !1, i.value = !0;
|
|
23
|
+
} finally {
|
|
24
|
+
r.value = !1;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
config: o,
|
|
29
|
+
isLoading: r,
|
|
30
|
+
syncStrategyDetected: i,
|
|
31
|
+
isLocalOnlyMode: a,
|
|
32
|
+
detectSyncStrategy
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { useAuthUI };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=useAuthUI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuthUI.mjs","names":[],"sources":["../../src/composables/useAuthUI.ts"],"sourcesContent":["import { ref, computed } from 'vue';\nimport { getCurrentUser } from '../stores/useAuthStore';\n\nexport interface AuthUIConfig {\n showLoginRegistration: boolean;\n showLogout: boolean;\n showResetData: boolean;\n logoutLabel: string;\n resetLabel: string;\n}\n\nexport function useAuthUI() {\n const isLoading = ref(true);\n const syncStrategyDetected = ref(false);\n const isLocalOnlyMode = ref(false);\n\n const config = computed<AuthUIConfig>(() => {\n if (isLocalOnlyMode.value) {\n return {\n showLoginRegistration: false,\n showLogout: false,\n showResetData: true,\n logoutLabel: '',\n resetLabel: 'Reset User Data',\n };\n } else {\n return {\n showLoginRegistration: true,\n showLogout: true,\n showResetData: false,\n logoutLabel: 'Log out',\n resetLabel: '',\n };\n }\n });\n\n const detectSyncStrategy = async () => {\n try {\n isLoading.value = true;\n const user = await getCurrentUser();\n \n // Access the sync strategy through the user's private syncStrategy property\n // NoOpSyncStrategy (local-only) returns false for canCreateAccount\n // CouchDBSyncStrategy (remote sync) returns true for canCreateAccount\n const userInternal = user as { syncStrategy?: { canCreateAccount?: () => boolean } };\n const canCreateAccount = userInternal.syncStrategy?.canCreateAccount?.();\n \n isLocalOnlyMode.value = !canCreateAccount;\n syncStrategyDetected.value = true;\n } catch (error) {\n console.error('Failed to detect sync strategy:', error);\n // Default to remote sync mode on error\n isLocalOnlyMode.value = false;\n syncStrategyDetected.value = true;\n } finally {\n isLoading.value = false;\n }\n };\n\n return {\n config,\n isLoading,\n syncStrategyDetected,\n isLocalOnlyMode,\n detectSyncStrategy,\n };\n}"],"mappings":";;;;AAWA,SAAgB,YAAY;CAC1B,IAAM,IAAY,EAAI,GAAK,EACrB,IAAuB,EAAI,GAAM,EACjC,IAAkB,EAAI,GAAM,EAE5B,IAAS,QACT,EAAgB,QACX;EACL,uBAAuB;EACvB,YAAY;EACZ,eAAe;EACf,aAAa;EACb,YAAY;EACb,GAEM;EACL,uBAAuB;EACvB,YAAY;EACZ,eAAe;EACf,aAAa;EACb,YAAY;EACb,CAEH,EAEI,qBAAqB,YAAY;AACrC,MAAI;AAWF,GAVA,EAAU,QAAQ,IASlB,EAAgB,QAAQ,EARX,MAAM,GAAgB,EAMG,cAAc,oBAAoB,EAGxE,EAAqB,QAAQ;WACtB,GAAO;AAId,GAHA,QAAQ,MAAM,mCAAmC,EAAM,EAEvD,EAAgB,QAAQ,IACxB,EAAqB,QAAQ;YACrB;AACR,KAAU,QAAQ;;;AAItB,QAAO;EACL;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { getUserStatus as e } from "../services/authAPI.mjs";
|
|
3
|
+
import { computed as t, ref as n } from "vue";
|
|
4
|
+
//#region src/composables/useEntitlements.ts
|
|
5
|
+
function useEntitlements(r) {
|
|
6
|
+
let i = n({}), a = n(!1), o = n(null), s = t(() => {
|
|
7
|
+
let e = i.value[r];
|
|
8
|
+
if (!e) return {
|
|
9
|
+
isActive: !1,
|
|
10
|
+
isPaid: !1,
|
|
11
|
+
daysRemaining: null,
|
|
12
|
+
expiresDate: null
|
|
13
|
+
};
|
|
14
|
+
if (e.status === "paid") return {
|
|
15
|
+
isActive: !0,
|
|
16
|
+
isPaid: !0,
|
|
17
|
+
daysRemaining: null,
|
|
18
|
+
expiresDate: null
|
|
19
|
+
};
|
|
20
|
+
let t = e.expires;
|
|
21
|
+
if (!t) return {
|
|
22
|
+
isActive: !0,
|
|
23
|
+
isPaid: !1,
|
|
24
|
+
daysRemaining: null,
|
|
25
|
+
expiresDate: null
|
|
26
|
+
};
|
|
27
|
+
let n = new Date(t), a = /* @__PURE__ */ new Date(), o = Math.ceil((n.getTime() - a.getTime()) / (1e3 * 60 * 60 * 24));
|
|
28
|
+
return {
|
|
29
|
+
isActive: o > 0,
|
|
30
|
+
isPaid: !1,
|
|
31
|
+
daysRemaining: Math.max(0, o),
|
|
32
|
+
expiresDate: t
|
|
33
|
+
};
|
|
34
|
+
}), c = t(() => s.value.isPaid);
|
|
35
|
+
async function fetchEntitlements() {
|
|
36
|
+
a.value = !0, o.value = null;
|
|
37
|
+
try {
|
|
38
|
+
let t = await e();
|
|
39
|
+
t.ok ? i.value = t.entitlements || {} : (o.value = t.error || "Failed to fetch entitlements", console.error("[useEntitlements] Error:", o.value));
|
|
40
|
+
} catch (e) {
|
|
41
|
+
o.value = e instanceof Error ? e.message : "Unknown error", console.error("[useEntitlements] Exception:", e);
|
|
42
|
+
} finally {
|
|
43
|
+
a.value = !1;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
entitlements: i,
|
|
48
|
+
trialStatus: s,
|
|
49
|
+
hasPremiumAccess: c,
|
|
50
|
+
loading: a,
|
|
51
|
+
error: o,
|
|
52
|
+
fetchEntitlements
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { useEntitlements };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=useEntitlements.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEntitlements.mjs","names":[],"sources":["../../src/composables/useEntitlements.ts"],"sourcesContent":["import { ref, computed } from 'vue';\nimport { getUserStatus } from '../services/authAPI';\nimport type { Entitlement, UserEntitlements } from '../services/authAPI';\n\nexport interface TrialStatus {\n isActive: boolean;\n isPaid: boolean;\n daysRemaining: number | null;\n expiresDate: string | null;\n}\n\n/**\n * Composable for managing user entitlements and trial status\n *\n * @param courseId - The course identifier to check entitlements for\n * @returns Object with entitlements data and helper methods\n *\n * @example\n * ```typescript\n * const { trialStatus, hasPremiumAccess, fetchEntitlements, loading } = useEntitlements('letterspractice-basic');\n *\n * onMounted(async () => {\n * await fetchEntitlements();\n * console.log('Days remaining:', trialStatus.value.daysRemaining);\n * });\n * ```\n */\nexport function useEntitlements(courseId: string) {\n const entitlements = ref<UserEntitlements>({});\n const loading = ref(false);\n const error = ref<string | null>(null);\n\n /**\n * Get trial status for the specified course\n */\n const trialStatus = computed<TrialStatus>(() => {\n const entitlement: Entitlement | undefined = entitlements.value[courseId];\n\n if (!entitlement) {\n return {\n isActive: false,\n isPaid: false,\n daysRemaining: null,\n expiresDate: null,\n };\n }\n\n if (entitlement.status === 'paid') {\n return {\n isActive: true,\n isPaid: true,\n daysRemaining: null,\n expiresDate: null,\n };\n }\n\n // Trial status\n const expiresDate = entitlement.expires;\n if (!expiresDate) {\n return {\n isActive: true,\n isPaid: false,\n daysRemaining: null,\n expiresDate: null,\n };\n }\n\n const expires = new Date(expiresDate);\n const now = new Date();\n const daysLeft = Math.ceil((expires.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));\n\n return {\n isActive: daysLeft > 0,\n isPaid: false,\n daysRemaining: Math.max(0, daysLeft),\n expiresDate,\n };\n });\n\n /**\n * Whether the user has premium (paid) access to the course\n */\n const hasPremiumAccess = computed<boolean>(() => {\n return trialStatus.value.isPaid;\n });\n\n /**\n * Fetch entitlements from the backend\n */\n async function fetchEntitlements(): Promise<void> {\n loading.value = true;\n error.value = null;\n\n try {\n const result = await getUserStatus();\n if (result.ok) {\n entitlements.value = result.entitlements || {};\n } else {\n error.value = result.error || 'Failed to fetch entitlements';\n console.error('[useEntitlements] Error:', error.value);\n }\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Unknown error';\n console.error('[useEntitlements] Exception:', e);\n } finally {\n loading.value = false;\n }\n }\n\n return {\n entitlements,\n trialStatus,\n hasPremiumAccess,\n loading,\n error,\n fetchEntitlements,\n };\n}\n"],"mappings":";;;;AA2BA,SAAgB,gBAAgB,GAAkB;CAChD,IAAM,IAAe,EAAsB,EAAE,CAAC,EACxC,IAAU,EAAI,GAAM,EACpB,IAAQ,EAAmB,KAAK,EAKhC,IAAc,QAA4B;EAC9C,IAAM,IAAuC,EAAa,MAAM;AAEhE,MAAI,CAAC,EACH,QAAO;GACL,UAAU;GACV,QAAQ;GACR,eAAe;GACf,aAAa;GACd;AAGH,MAAI,EAAY,WAAW,OACzB,QAAO;GACL,UAAU;GACV,QAAQ;GACR,eAAe;GACf,aAAa;GACd;EAIH,IAAM,IAAc,EAAY;AAChC,MAAI,CAAC,EACH,QAAO;GACL,UAAU;GACV,QAAQ;GACR,eAAe;GACf,aAAa;GACd;EAGH,IAAM,IAAU,IAAI,KAAK,EAAY,EAC/B,oBAAM,IAAI,MAAM,EAChB,IAAW,KAAK,MAAM,EAAQ,SAAS,GAAG,EAAI,SAAS,KAAK,MAAO,KAAK,KAAK,IAAI;AAEvF,SAAO;GACL,UAAU,IAAW;GACrB,QAAQ;GACR,eAAe,KAAK,IAAI,GAAG,EAAS;GACpC;GACD;GACD,EAKI,IAAmB,QAChB,EAAY,MAAM,OACzB;CAKF,eAAe,oBAAmC;AAEhD,EADA,EAAQ,QAAQ,IAChB,EAAM,QAAQ;AAEd,MAAI;GACF,IAAM,IAAS,MAAM,GAAe;AACpC,GAAI,EAAO,KACT,EAAa,QAAQ,EAAO,gBAAgB,EAAE,IAE9C,EAAM,QAAQ,EAAO,SAAS,gCAC9B,QAAQ,MAAM,4BAA4B,EAAM,MAAM;WAEjD,GAAG;AAEV,GADA,EAAM,QAAQ,aAAa,QAAQ,EAAE,UAAU,iBAC/C,QAAQ,MAAM,gCAAgC,EAAE;YACxC;AACR,KAAQ,QAAQ;;;AAIpB,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import e from "./components/HeatMap.mjs";
|
|
2
|
+
import { SkldrMouseTrap as t } from "./utils/SkldrMouseTrap.mjs";
|
|
3
|
+
import n from "./components/SkMouseTrap.mjs";
|
|
4
|
+
import r from "./components/SkMouseTrapToolTip.mjs";
|
|
5
|
+
import { alertUser as i } from "./components/SnackbarService.mjs";
|
|
6
|
+
import a from "./components/SnackbarService2.mjs";
|
|
7
|
+
import o from "./components/PaginatingToolbar.mjs";
|
|
8
|
+
import s from "./components/CardSearch.mjs";
|
|
9
|
+
import c from "./components/CardSearchResults.mjs";
|
|
10
|
+
import l from "./components/CardHistoryViewer.mjs";
|
|
11
|
+
import { isQuestionView as u, useQuestionView as d, useViewable as f } from "./composables/CompositionViewable.mjs";
|
|
12
|
+
import { Displayable as p, Question as m, isDefineComponent as h } from "./composables/Displayable.mjs";
|
|
13
|
+
import { getUserStatus as g, requestPasswordReset as _, resetPassword as v, resolveLoginIdentifier as y, sendVerificationEmail as b, verifyEmail as x } from "./services/authAPI.mjs";
|
|
14
|
+
import { useEntitlements as S } from "./composables/useEntitlements.mjs";
|
|
15
|
+
import C from "./components/StudySessionTimer.mjs";
|
|
16
|
+
import w from "./components/cardRendering/CardViewer.mjs";
|
|
17
|
+
import T from "./components/SessionControllerDebug.mjs";
|
|
18
|
+
import E from "./components/StudySession.mjs";
|
|
19
|
+
import { piniaPlugin as D } from "./plugins/pinia.mjs";
|
|
20
|
+
import { useCardPreviewModeStore as O } from "./stores/useCardPreviewModeStore.mjs";
|
|
21
|
+
import k from "./components/studentInputs/MultipleChoiceOption.mjs";
|
|
22
|
+
import A from "./components/studentInputs/RadioMultipleChoice.mjs";
|
|
23
|
+
import j from "./components/studentInputs/TrueFalse.mjs";
|
|
24
|
+
import M from "./components/studentInputs/UserInputNumber.mjs";
|
|
25
|
+
import N from "./components/studentInputs/UserInputString.mjs";
|
|
26
|
+
import P from "./components/studentInputs/fillInInput.mjs";
|
|
27
|
+
import F from "./components/cardRendering/CardLoader.mjs";
|
|
28
|
+
import { containsComponent as I, isComponent as L, isInlineComponent as R, parseComponentSyntax as z, parseComponentToken as B, splitByDelimiters as V, splitParagraphToken as H, splitTextToken as U } from "./components/cardRendering/MarkdownRendererHelpers.mjs";
|
|
29
|
+
import W from "./components/cardRendering/AudioAutoPlayer.mjs";
|
|
30
|
+
import G from "./components/cardRendering/CodeBlockRenderer.mjs";
|
|
31
|
+
import K from "./components/cardRendering/MdTokenRenderer.mjs";
|
|
32
|
+
import q from "./components/cardRendering/MarkdownRenderer.mjs";
|
|
33
|
+
import { getCurrentUser as J, useAuthStore as Y } from "./stores/useAuthStore.mjs";
|
|
34
|
+
import { useConfigStore as X } from "./stores/useConfigStore.mjs";
|
|
35
|
+
import Z from "./components/auth/UserChip.mjs";
|
|
36
|
+
import Q from "./components/auth/UserLogin.mjs";
|
|
37
|
+
import { isPasswordValid as $, validatePassword as ee } from "./utils/passwordValidation.mjs";
|
|
38
|
+
import te from "./components/auth/UserRegistration.mjs";
|
|
39
|
+
import ne from "./components/auth/RequestPasswordReset.mjs";
|
|
40
|
+
import re from "./components/auth/UserLoginAndRegistrationContainer.mjs";
|
|
41
|
+
import ie from "./components/auth/VerifyEmail.mjs";
|
|
42
|
+
import ae from "./components/auth/ResetPassword.mjs";
|
|
43
|
+
import oe from "./components/TagsInput.mjs";
|
|
44
|
+
import se from "./components/CourseCardBrowser.mjs";
|
|
45
|
+
import ce from "./components/CourseInformation.mjs";
|
|
46
|
+
import le from "./components/CardBrowser.mjs";
|
|
47
|
+
import ue from "./components/CourseTagFilterWidget.mjs";
|
|
48
|
+
import de from "./components/UserTagPreferences.mjs";
|
|
49
|
+
export { W as AudioAutoPlayer, le as CardBrowser, l as CardHistoryViewer, F as CardLoader, s as CardSearch, c as CardSearchResults, w as CardViewer, G as CodeBlockRenderer, se as CourseCardBrowser, ce as CourseInformation, ue as CourseTagFilterWidget, p as Displayable, P as FillInInput, e as HeatMap, q as MarkdownRenderer, K as MdTokenRenderer, k as MultipleChoiceOption, o as PaginatingToolbar, m as Question, A as RadioMultipleChoice, ne as RequestPasswordReset, ae as ResetPassword, T as SessionControllerDebug, n as SkMouseTrap, r as SkMouseTrapToolTip, t as SkldrMouseTrap, a as SnackbarService, E as StudySession, C as StudySessionTimer, j as TFSelect, oe as TagsInput, Z as UserChip, M as UserInputNumber, N as UserInputString, Q as UserLogin, re as UserLoginAndRegistrationContainer, te as UserRegistration, de as UserTagPreferences, ie as VerifyEmail, i as alertUser, I as containsComponent, J as getCurrentUser, g as getUserStatus, L as isComponent, h as isDefineComponent, R as isInlineComponent, $ as isPasswordValid, u as isQuestionView, z as parseComponentSyntax, B as parseComponentToken, D as piniaPlugin, _ as requestPasswordReset, v as resetPassword, y as resolveLoginIdentifier, b as sendVerificationEmail, V as splitByDelimiters, H as splitParagraphToken, U as splitTextToken, Y as useAuthStore, O as useCardPreviewModeStore, X as useConfigStore, S as useEntitlements, d as useQuestionView, f as useViewable, ee as validatePassword, x as verifyEmail };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
//#region src/plugins/pinia.ts
|
|
3
|
+
var e = null, setPinia = (t) => {
|
|
4
|
+
e = t;
|
|
5
|
+
}, getPinia = () => e, t = { install(e, t) {
|
|
6
|
+
let n = t?.pinia;
|
|
7
|
+
n && setPinia(n);
|
|
8
|
+
} };
|
|
9
|
+
//#endregion
|
|
10
|
+
export { getPinia, t as piniaPlugin };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=pinia.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinia.mjs","names":[],"sources":["../../src/plugins/pinia.ts"],"sourcesContent":["// common-ui/src/plugins/pinia.ts\nimport { Plugin } from 'vue';\nimport { Pinia } from 'pinia';\n\n// This will hold the Pinia instance provided by the main app\nlet _pinia: Pinia | null = null;\n\nexport const setPinia = (pinia: Pinia) => {\n _pinia = pinia;\n};\n\nexport const getPinia = (): Pinia | null => {\n return _pinia;\n};\n\n// Create a plugin that the main app can use\nexport const piniaPlugin: Plugin = {\n install(_app, options) {\n const pinia = options?.pinia;\n if (pinia) {\n setPinia(pinia);\n }\n },\n};\n"],"mappings":";;AAKA,IAAI,IAAuB,MAEd,YAAY,MAAiB;AACxC,KAAS;GAGE,iBACJ,GAII,IAAsB,EACjC,QAAQ,GAAM,GAAS;CACrB,IAAM,IAAQ,GAAS;AACvB,CAAI,KACF,SAAS,EAAM;GAGpB"}
|