@things-factory/learning 0.0.0-stage → 10.1.260

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 (149) hide show
  1. package/dist-client/bootstrap.d.ts +2 -0
  2. package/dist-client/bootstrap.js +4 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/components/learning-assign-form.d.ts +24 -0
  5. package/dist-client/components/learning-assign-form.js +77 -0
  6. package/dist-client/components/learning-assign-form.js.map +1 -0
  7. package/dist-client/components/learning-course-form.d.ts +29 -0
  8. package/dist-client/components/learning-course-form.js +104 -0
  9. package/dist-client/components/learning-course-form.js.map +1 -0
  10. package/dist-client/components/learning-question-form.d.ts +33 -0
  11. package/dist-client/components/learning-question-form.js +142 -0
  12. package/dist-client/components/learning-question-form.js.map +1 -0
  13. package/dist-client/components/learning-todo.d.ts +12 -0
  14. package/dist-client/components/learning-todo.js +43 -0
  15. package/dist-client/components/learning-todo.js.map +1 -0
  16. package/dist-client/components/learning-unit-form.d.ts +41 -0
  17. package/dist-client/components/learning-unit-form.js +143 -0
  18. package/dist-client/components/learning-unit-form.js.map +1 -0
  19. package/dist-client/index.d.ts +2 -0
  20. package/dist-client/index.js +3 -0
  21. package/dist-client/index.js.map +1 -0
  22. package/dist-client/pages/learning-course-editor.d.ts +62 -0
  23. package/dist-client/pages/learning-course-editor.js +463 -0
  24. package/dist-client/pages/learning-course-editor.js.map +1 -0
  25. package/dist-client/pages/learning-course-list.d.ts +37 -0
  26. package/dist-client/pages/learning-course-list.js +88 -0
  27. package/dist-client/pages/learning-course-list.js.map +1 -0
  28. package/dist-client/pages/learning-enrollment-status.d.ts +53 -0
  29. package/dist-client/pages/learning-enrollment-status.js +228 -0
  30. package/dist-client/pages/learning-enrollment-status.js.map +1 -0
  31. package/dist-client/pages/learning-view.d.ts +52 -0
  32. package/dist-client/pages/learning-view.js +371 -0
  33. package/dist-client/pages/learning-view.js.map +1 -0
  34. package/dist-client/pages/my-learning.d.ts +22 -0
  35. package/dist-client/pages/my-learning.js +110 -0
  36. package/dist-client/pages/my-learning.js.map +1 -0
  37. package/dist-client/route.d.ts +1 -0
  38. package/dist-client/route.js +21 -0
  39. package/dist-client/route.js.map +1 -0
  40. package/dist-client/tsconfig.tsbuildinfo +1 -0
  41. package/dist-client/utils/learning-api.d.ts +16 -0
  42. package/dist-client/utils/learning-api.js +36 -0
  43. package/dist-client/utils/learning-api.js.map +1 -0
  44. package/dist-client/utils/learning-words.d.ts +20 -0
  45. package/dist-client/utils/learning-words.js +22 -0
  46. package/dist-client/utils/learning-words.js.map +1 -0
  47. package/dist-server/activities.d.ts +38 -0
  48. package/dist-server/activities.js +42 -0
  49. package/dist-server/activities.js.map +1 -0
  50. package/dist-server/ai-reads.d.ts +9 -0
  51. package/dist-server/ai-reads.js +70 -0
  52. package/dist-server/ai-reads.js.map +1 -0
  53. package/dist-server/attachment-reader.d.ts +1 -0
  54. package/dist-server/attachment-reader.js +23 -0
  55. package/dist-server/attachment-reader.js.map +1 -0
  56. package/dist-server/index.d.ts +4 -0
  57. package/dist-server/index.js +33 -0
  58. package/dist-server/index.js.map +1 -0
  59. package/dist-server/learning-subjects.d.ts +10 -0
  60. package/dist-server/learning-subjects.js +31 -0
  61. package/dist-server/learning-subjects.js.map +1 -0
  62. package/dist-server/role-tasks.d.ts +2 -0
  63. package/dist-server/role-tasks.js +17 -0
  64. package/dist-server/role-tasks.js.map +1 -0
  65. package/dist-server/service/course/course-mutation.d.ts +19 -0
  66. package/dist-server/service/course/course-mutation.js +176 -0
  67. package/dist-server/service/course/course-mutation.js.map +1 -0
  68. package/dist-server/service/course/course-query.d.ts +26 -0
  69. package/dist-server/service/course/course-query.js +172 -0
  70. package/dist-server/service/course/course-query.js.map +1 -0
  71. package/dist-server/service/course/course-question.d.ts +41 -0
  72. package/dist-server/service/course/course-question.js +116 -0
  73. package/dist-server/service/course/course-question.js.map +1 -0
  74. package/dist-server/service/course/course-rules.d.ts +49 -0
  75. package/dist-server/service/course/course-rules.js +89 -0
  76. package/dist-server/service/course/course-rules.js.map +1 -0
  77. package/dist-server/service/course/course-service.d.ts +71 -0
  78. package/dist-server/service/course/course-service.js +402 -0
  79. package/dist-server/service/course/course-service.js.map +1 -0
  80. package/dist-server/service/course/course-type.d.ts +55 -0
  81. package/dist-server/service/course/course-type.js +198 -0
  82. package/dist-server/service/course/course-type.js.map +1 -0
  83. package/dist-server/service/course/course-unit.d.ts +36 -0
  84. package/dist-server/service/course/course-unit.js +123 -0
  85. package/dist-server/service/course/course-unit.js.map +1 -0
  86. package/dist-server/service/course/course-version.d.ts +45 -0
  87. package/dist-server/service/course/course-version.js +151 -0
  88. package/dist-server/service/course/course-version.js.map +1 -0
  89. package/dist-server/service/course/course.d.ts +23 -0
  90. package/dist-server/service/course/course.js +92 -0
  91. package/dist-server/service/course/course.js.map +1 -0
  92. package/dist-server/service/course/index.d.ts +14 -0
  93. package/dist-server/service/course/index.js +24 -0
  94. package/dist-server/service/course/index.js.map +1 -0
  95. package/dist-server/service/enrollment/enrollment-mutation.d.ts +11 -0
  96. package/dist-server/service/enrollment/enrollment-mutation.js +124 -0
  97. package/dist-server/service/enrollment/enrollment-mutation.js.map +1 -0
  98. package/dist-server/service/enrollment/enrollment-query.d.ts +23 -0
  99. package/dist-server/service/enrollment/enrollment-query.js +245 -0
  100. package/dist-server/service/enrollment/enrollment-query.js.map +1 -0
  101. package/dist-server/service/enrollment/enrollment-remind.d.ts +1 -0
  102. package/dist-server/service/enrollment/enrollment-remind.js +45 -0
  103. package/dist-server/service/enrollment/enrollment-remind.js.map +1 -0
  104. package/dist-server/service/enrollment/enrollment-service.d.ts +110 -0
  105. package/dist-server/service/enrollment/enrollment-service.js +417 -0
  106. package/dist-server/service/enrollment/enrollment-service.js.map +1 -0
  107. package/dist-server/service/enrollment/enrollment-status.d.ts +40 -0
  108. package/dist-server/service/enrollment/enrollment-status.js +135 -0
  109. package/dist-server/service/enrollment/enrollment-status.js.map +1 -0
  110. package/dist-server/service/enrollment/enrollment-type.d.ts +95 -0
  111. package/dist-server/service/enrollment/enrollment-type.js +341 -0
  112. package/dist-server/service/enrollment/enrollment-type.js.map +1 -0
  113. package/dist-server/service/enrollment/enrollment.d.ts +52 -0
  114. package/dist-server/service/enrollment/enrollment.js +186 -0
  115. package/dist-server/service/enrollment/enrollment.js.map +1 -0
  116. package/dist-server/service/enrollment/index.d.ts +15 -0
  117. package/dist-server/service/enrollment/index.js +26 -0
  118. package/dist-server/service/enrollment/index.js.map +1 -0
  119. package/dist-server/service/enrollment/learning-ai.d.ts +38 -0
  120. package/dist-server/service/enrollment/learning-ai.js +96 -0
  121. package/dist-server/service/enrollment/learning-ai.js.map +1 -0
  122. package/dist-server/service/enrollment/learning-documents.d.ts +7 -0
  123. package/dist-server/service/enrollment/learning-documents.js +160 -0
  124. package/dist-server/service/enrollment/learning-documents.js.map +1 -0
  125. package/dist-server/service/enrollment/learning-outcome.d.ts +10 -0
  126. package/dist-server/service/enrollment/learning-outcome.js +16 -0
  127. package/dist-server/service/enrollment/learning-outcome.js.map +1 -0
  128. package/dist-server/service/enrollment/progress-rules.d.ts +94 -0
  129. package/dist-server/service/enrollment/progress-rules.js +97 -0
  130. package/dist-server/service/enrollment/progress-rules.js.map +1 -0
  131. package/dist-server/service/enrollment/quiz-attempt.d.ts +34 -0
  132. package/dist-server/service/enrollment/quiz-attempt.js +105 -0
  133. package/dist-server/service/enrollment/quiz-attempt.js.map +1 -0
  134. package/dist-server/service/enrollment/unit-progress.d.ts +30 -0
  135. package/dist-server/service/enrollment/unit-progress.js +114 -0
  136. package/dist-server/service/enrollment/unit-progress.js.map +1 -0
  137. package/dist-server/service/index.d.ts +14 -0
  138. package/dist-server/service/index.js +43 -0
  139. package/dist-server/service/index.js.map +1 -0
  140. package/dist-server/tsconfig.tsbuildinfo +1 -0
  141. package/package.json +56 -4
  142. package/things-factory.config.js +14 -0
  143. package/translations/en.json +255 -0
  144. package/translations/es.json +255 -0
  145. package/translations/ja.json +255 -0
  146. package/translations/ko.json +255 -0
  147. package/translations/ms.json +255 -0
  148. package/translations/zh.json +255 -0
  149. package/README.md +0 -3
@@ -0,0 +1,2 @@
1
+ import './components/learning-todo.js';
2
+ export default function bootstrap(): void;
@@ -0,0 +1,4 @@
1
+ import './components/learning-todo.js';
2
+ /* The to-do's element registers itself on load - the pages come in through the route when an application puts them in its menu. */
3
+ export default function bootstrap() { }
4
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,+BAA+B,CAAA;AAEtC,mIAAmI;AACnI,MAAM,CAAC,OAAO,UAAU,SAAS,KAAI,CAAC","sourcesContent":["import './components/learning-todo.js'\n\n/* The to-do's element registers itself on load - the pages come in through the route when an application puts them in its menu. */\nexport default function bootstrap() {}\n"]}
@@ -0,0 +1,24 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import '@material/web/button/text-button.js';
3
+ import '@operato/popup/ox-popup-actions.js';
4
+ import '@things-factory/announcement/dist-client';
5
+ import { LitElement } from 'lit';
6
+ /** Opens the assignment form of a course. Resolves with how many enrolments it holds now, or null. */
7
+ export declare function openAssignForm(course: {
8
+ id: string;
9
+ name: string;
10
+ }): Promise<number | null>;
11
+ declare const LearningAssignForm_base: (new (...args: any[]) => LitElement) & typeof LitElement;
12
+ export declare class LearningAssignForm extends LearningAssignForm_base {
13
+ static styles: import("lit").CSSResult[];
14
+ course: {
15
+ id: string;
16
+ name: string;
17
+ };
18
+ private audiences;
19
+ private dueOn;
20
+ private assign;
21
+ render(): import("lit-html").TemplateResult<1>;
22
+ private submit;
23
+ }
24
+ export {};
@@ -0,0 +1,77 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/button/filled-button.js';
3
+ import '@material/web/button/text-button.js';
4
+ import '@operato/popup/ox-popup-actions.js';
5
+ import '@things-factory/announcement/dist-client';
6
+ import gql from 'graphql-tag';
7
+ import { html, LitElement, nothing } from 'lit';
8
+ import { customElement, property, state } from 'lit/decorators.js';
9
+ import { MutationController } from '@operato/graphql';
10
+ import { i18next, localize } from '@operato/i18n';
11
+ import { openPopup } from '@operato/layout';
12
+ import { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles';
13
+ import { t } from '../utils/learning-words.js';
14
+ /** Opens the assignment form of a course. Resolves with how many enrolments it holds now, or null. */
15
+ export function openAssignForm(course) {
16
+ const popup = openPopup(html `<learning-assign-form .course=${course} @assigned=${(e) => popup.close(e.detail)} @close=${() => popup.close()}></learning-assign-form>`, { backdrop: true, size: 'medium', title: t('title.learning-assign', { course: course.name }) });
17
+ return popup.result.then(value => (value ?? null));
18
+ }
19
+ /*
20
+ * 수강 배정 (ADR-0194 decision 7) - whom a course is assigned to, by the one audience rule (the domain, departments with
21
+ * those under them, roles and people - ADR-0163), and the day it is due. Each person gets a to-do.
22
+ */
23
+ let LearningAssignForm = class LearningAssignForm extends localize(i18next)(LitElement) {
24
+ constructor() {
25
+ super(...arguments);
26
+ this.course = { id: '', name: '' };
27
+ this.audiences = [];
28
+ this.dueOn = '';
29
+ this.assign = new MutationController(this, gql `mutation ($courseId: String!, $audiences: [LearningAudienceInput!]!, $dueOn: String) { assignCourse(courseId: $courseId, audiences: $audiences, dueOn: $dueOn) { id } }`, { showsError: true });
30
+ }
31
+ static { this.styles = [CommonPopupStyles, PopupBodyStyles, FormFieldStyles, PopupFieldStyles]; }
32
+ render() {
33
+ const error = this.assign.error;
34
+ return html `
35
+ <div class="body">
36
+ <div class="field">
37
+ <span>${t('field.learning-assign-audience')}</span>
38
+ <announcement-audience-picker .value=${this.audiences} @change=${(e) => Array.isArray(e.detail) && (this.audiences = e.detail)}></announcement-audience-picker>
39
+ <span>${t('text.learning-assign-audience-hint')}</span>
40
+ </div>
41
+ <label class="field">
42
+ <span>${t('field.learning-due-on')}</span>
43
+ <input type="date" .value=${this.dueOn} @input=${(e) => (this.dueOn = e.target.value)} />
44
+ <span>${t('text.learning-due-on-hint')}</span>
45
+ </label>
46
+ ${error ? html `<div class="field"><span invalid role="alert">${error.graphQLErrors?.[0]?.message ?? error.message}</span></div>` : nothing}
47
+ </div>
48
+ <ox-popup-actions>
49
+ <md-text-button slot="cancel" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${t('button.cancel')}</md-text-button>
50
+ <md-filled-button slot="confirm" ?disabled=${!this.audiences.length || this.assign.pending} @click=${() => this.submit()}>${t('button.learning-assign')}</md-filled-button>
51
+ </ox-popup-actions>
52
+ `;
53
+ }
54
+ async submit() {
55
+ const audiences = this.audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName }));
56
+ const done = await this.assign.run({ courseId: this.course.id, audiences, dueOn: this.dueOn || null });
57
+ if (done)
58
+ this.dispatchEvent(new CustomEvent('assigned', { detail: done.assignCourse.length }));
59
+ }
60
+ };
61
+ __decorate([
62
+ property({ attribute: false }),
63
+ __metadata("design:type", Object)
64
+ ], LearningAssignForm.prototype, "course", void 0);
65
+ __decorate([
66
+ state(),
67
+ __metadata("design:type", Array)
68
+ ], LearningAssignForm.prototype, "audiences", void 0);
69
+ __decorate([
70
+ state(),
71
+ __metadata("design:type", Object)
72
+ ], LearningAssignForm.prototype, "dueOn", void 0);
73
+ LearningAssignForm = __decorate([
74
+ customElement('learning-assign-form')
75
+ ], LearningAssignForm);
76
+ export { LearningAssignForm };
77
+ //# sourceMappingURL=learning-assign-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-assign-form.js","sourceRoot":"","sources":["../../client/components/learning-assign-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport '@things-factory/announcement/dist-client'\n\nimport gql from 'graphql-tag'\nimport { html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { MutationController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles'\n\nimport { t } from '../utils/learning-words.js'\n\n/** Opens the assignment form of a course. Resolves with how many enrolments it holds now, or null. */\nexport function openAssignForm(course: { id: string; name: string }): Promise<number | null> {\n const popup = openPopup(html`<learning-assign-form .course=${course} @assigned=${(e: CustomEvent) => popup.close(e.detail)} @close=${() => popup.close()}></learning-assign-form>`, { backdrop: true, size: 'medium', title: t('title.learning-assign', { course: course.name }) })\n return popup.result.then(value => (value ?? null) as any)\n}\n\n/*\n * 수강 배정 (ADR-0194 decision 7) - whom a course is assigned to, by the one audience rule (the domain, departments with\n * those under them, roles and people - ADR-0163), and the day it is due. Each person gets a to-do.\n */\n@customElement('learning-assign-form')\nexport class LearningAssignForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormFieldStyles, PopupFieldStyles]\n\n @property({ attribute: false }) course: { id: string; name: string } = { id: '', name: '' }\n @state() private audiences: { scope: string; targetId: string; targetName?: string }[] = []\n @state() private dueOn = ''\n\n private assign = new MutationController(this, gql`mutation ($courseId: String!, $audiences: [LearningAudienceInput!]!, $dueOn: String) { assignCourse(courseId: $courseId, audiences: $audiences, dueOn: $dueOn) { id } }`, { showsError: true })\n\n render() {\n const error: any = this.assign.error\n return html`\n <div class=\"body\">\n <div class=\"field\">\n <span>${t('field.learning-assign-audience')}</span>\n <announcement-audience-picker .value=${this.audiences} @change=${(e: CustomEvent) => Array.isArray(e.detail) && (this.audiences = e.detail)}></announcement-audience-picker>\n <span>${t('text.learning-assign-audience-hint')}</span>\n </div>\n <label class=\"field\">\n <span>${t('field.learning-due-on')}</span>\n <input type=\"date\" .value=${this.dueOn} @input=${(e: any) => (this.dueOn = e.target.value)} />\n <span>${t('text.learning-due-on-hint')}</span>\n </label>\n ${error ? html`<div class=\"field\"><span invalid role=\"alert\">${error.graphQLErrors?.[0]?.message ?? error.message}</span></div>` : nothing}\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${t('button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${!this.audiences.length || this.assign.pending} @click=${() => this.submit()}>${t('button.learning-assign')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private async submit() {\n const audiences = this.audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName }))\n const done = await this.assign.run({ courseId: this.course.id, audiences, dueOn: this.dueOn || null })\n if (done) this.dispatchEvent(new CustomEvent('assigned', { detail: done.assignCourse.length }))\n }\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import '@material/web/button/text-button.js';
3
+ import '@operato/input/ox-input-select-buttons.js';
4
+ import '@operato/popup/ox-popup-actions.js';
5
+ import { LitElement } from 'lit';
6
+ type CourseShape = {
7
+ id?: string;
8
+ name?: string;
9
+ category?: string | null;
10
+ description?: string | null;
11
+ };
12
+ /** Opens the course form - a new course, or what one says changed. Resolves with the course saved, or null. */
13
+ export declare function openCourseForm(course?: CourseShape): Promise<{
14
+ id: string;
15
+ } | null>;
16
+ declare const LearningCourseForm_base: (new (...args: any[]) => LitElement) & typeof LitElement;
17
+ export declare class LearningCourseForm extends LearningCourseForm_base {
18
+ static styles: import("lit").CSSResult[];
19
+ course: CourseShape;
20
+ private name;
21
+ private category;
22
+ private description;
23
+ private save;
24
+ private change;
25
+ willUpdate(changed: Map<string, unknown>): void;
26
+ render(): import("lit-html").TemplateResult<1>;
27
+ private submit;
28
+ }
29
+ export {};
@@ -0,0 +1,104 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/button/filled-button.js';
3
+ import '@material/web/button/text-button.js';
4
+ import '@operato/input/ox-input-select-buttons.js';
5
+ import '@operato/popup/ox-popup-actions.js';
6
+ import gql from 'graphql-tag';
7
+ import { css, html, LitElement, nothing } from 'lit';
8
+ import { customElement, property, state } from 'lit/decorators.js';
9
+ import { MutationController } from '@operato/graphql';
10
+ import { i18next, localize } from '@operato/i18n';
11
+ import { openPopup } from '@operato/layout';
12
+ import { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles';
13
+ import { CATEGORIES, categoryWord, t } from '../utils/learning-words.js';
14
+ /** Opens the course form - a new course, or what one says changed. Resolves with the course saved, or null. */
15
+ export function openCourseForm(course = {}) {
16
+ const popup = openPopup(html `<learning-course-form .course=${course} @saved=${(e) => popup.close(e.detail)} @close=${() => popup.close()}></learning-course-form>`, { backdrop: true, size: 'medium', title: course.id ? t('title.learning-course-edit') : t('title.learning-course-new') });
17
+ return popup.result.then(value => (value ?? null));
18
+ }
19
+ /* 과정 (ADR-0194 decision 2) - its name, category and description. The house shape of a popup: only the body scrolls, labels above native inputs, one action row. */
20
+ let LearningCourseForm = class LearningCourseForm extends localize(i18next)(LitElement) {
21
+ constructor() {
22
+ super(...arguments);
23
+ this.course = {};
24
+ this.name = '';
25
+ this.category = 'MANDATORY';
26
+ this.description = '';
27
+ this.save = new MutationController(this, gql `mutation ($course: NewCourse!) { createCourse(course: $course) { id } }`, { showsError: true });
28
+ this.change = new MutationController(this, gql `mutation ($id: String!, $patch: CoursePatch!) { updateCourse(id: $id, patch: $patch) { id } }`, { showsError: true });
29
+ }
30
+ static { this.styles = [
31
+ CommonPopupStyles,
32
+ PopupBodyStyles,
33
+ FormFieldStyles,
34
+ PopupFieldStyles,
35
+ css `
36
+ ox-input-select-buttons {
37
+ align-self: flex-start;
38
+ }
39
+ textarea {
40
+ min-height: 120px;
41
+ resize: vertical;
42
+ }
43
+ `
44
+ ]; }
45
+ willUpdate(changed) {
46
+ if (changed.has('course')) {
47
+ this.name = this.course.name ?? '';
48
+ this.category = this.course.category ?? 'MANDATORY';
49
+ this.description = this.course.description ?? '';
50
+ }
51
+ }
52
+ render() {
53
+ const pending = this.save.pending || this.change.pending;
54
+ const error = this.save.error || this.change.error;
55
+ return html `
56
+ <div class="body">
57
+ <label class="field">
58
+ <span>${t('field.learning-course-name')}</span>
59
+ <input .value=${this.name} maxlength="200" required @input=${(e) => (this.name = e.target.value)} />
60
+ </label>
61
+ <div class="field">
62
+ <span>${t('field.learning-course-category')}</span>
63
+ <ox-input-select-buttons .value=${this.category} .options=${CATEGORIES.map(code => ({ display: categoryWord(code), value: code }))} @change=${(e) => e.detail && (this.category = e.detail)}></ox-input-select-buttons>
64
+ </div>
65
+ <label class="field">
66
+ <span>${t('field.learning-course-description')}</span>
67
+ <textarea .value=${this.description} @input=${(e) => (this.description = e.target.value)}></textarea>
68
+ </label>
69
+ ${error ? html `<div class="field"><span invalid role="alert">${error.graphQLErrors?.[0]?.message ?? error.message}</span></div>` : nothing}
70
+ </div>
71
+ <ox-popup-actions>
72
+ <md-text-button slot="cancel" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${t('button.cancel')}</md-text-button>
73
+ <md-filled-button slot="confirm" ?disabled=${!this.name.trim() || pending} @click=${() => this.submit()}>${t('button.save')}</md-filled-button>
74
+ </ox-popup-actions>
75
+ `;
76
+ }
77
+ async submit() {
78
+ const fields = { name: this.name.trim(), category: this.category, description: this.description.trim() || null };
79
+ const done = this.course.id ? (await this.change.run({ id: this.course.id, patch: fields }))?.updateCourse : (await this.save.run({ course: fields }))?.createCourse;
80
+ if (done)
81
+ this.dispatchEvent(new CustomEvent('saved', { detail: done }));
82
+ }
83
+ };
84
+ __decorate([
85
+ property({ attribute: false }),
86
+ __metadata("design:type", Object)
87
+ ], LearningCourseForm.prototype, "course", void 0);
88
+ __decorate([
89
+ state(),
90
+ __metadata("design:type", Object)
91
+ ], LearningCourseForm.prototype, "name", void 0);
92
+ __decorate([
93
+ state(),
94
+ __metadata("design:type", Object)
95
+ ], LearningCourseForm.prototype, "category", void 0);
96
+ __decorate([
97
+ state(),
98
+ __metadata("design:type", Object)
99
+ ], LearningCourseForm.prototype, "description", void 0);
100
+ LearningCourseForm = __decorate([
101
+ customElement('learning-course-form')
102
+ ], LearningCourseForm);
103
+ export { LearningCourseForm };
104
+ //# sourceMappingURL=learning-course-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-course-form.js","sourceRoot":"","sources":["../../client/components/learning-course-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { MutationController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles'\n\nimport { CATEGORIES, categoryWord, t } from '../utils/learning-words.js'\n\ntype CourseShape = { id?: string; name?: string; category?: string | null; description?: string | null }\n\n/** Opens the course form - a new course, or what one says changed. Resolves with the course saved, or null. */\nexport function openCourseForm(course: CourseShape = {}): Promise<{ id: string } | null> {\n const popup = openPopup(html`<learning-course-form .course=${course} @saved=${(e: CustomEvent) => popup.close(e.detail)} @close=${() => popup.close()}></learning-course-form>`, { backdrop: true, size: 'medium', title: course.id ? t('title.learning-course-edit') : t('title.learning-course-new') })\n return popup.result.then(value => (value ?? null) as any)\n}\n\n/* 과정 (ADR-0194 decision 2) - its name, category and description. The house shape of a popup: only the body scrolls, labels above native inputs, one action row. */\n@customElement('learning-course-form')\nexport class LearningCourseForm extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n FormFieldStyles,\n PopupFieldStyles,\n css`\n ox-input-select-buttons {\n align-self: flex-start;\n }\n textarea {\n min-height: 120px;\n resize: vertical;\n }\n `\n ]\n\n @property({ attribute: false }) course: CourseShape = {}\n @state() private name = ''\n @state() private category = 'MANDATORY'\n @state() private description = ''\n\n private save = new MutationController(this, gql`mutation ($course: NewCourse!) { createCourse(course: $course) { id } }`, { showsError: true })\n private change = new MutationController(this, gql`mutation ($id: String!, $patch: CoursePatch!) { updateCourse(id: $id, patch: $patch) { id } }`, { showsError: true })\n\n willUpdate(changed: Map<string, unknown>) {\n if (changed.has('course')) {\n this.name = this.course.name ?? ''\n this.category = this.course.category ?? 'MANDATORY'\n this.description = this.course.description ?? ''\n }\n }\n\n render() {\n const pending = this.save.pending || this.change.pending\n const error: any = this.save.error || this.change.error\n return html`\n <div class=\"body\">\n <label class=\"field\">\n <span>${t('field.learning-course-name')}</span>\n <input .value=${this.name} maxlength=\"200\" required @input=${(e: any) => (this.name = e.target.value)} />\n </label>\n <div class=\"field\">\n <span>${t('field.learning-course-category')}</span>\n <ox-input-select-buttons .value=${this.category} .options=${CATEGORIES.map(code => ({ display: categoryWord(code), value: code }))} @change=${(e: CustomEvent) => e.detail && (this.category = e.detail)}></ox-input-select-buttons>\n </div>\n <label class=\"field\">\n <span>${t('field.learning-course-description')}</span>\n <textarea .value=${this.description} @input=${(e: any) => (this.description = e.target.value)}></textarea>\n </label>\n ${error ? html`<div class=\"field\"><span invalid role=\"alert\">${error.graphQLErrors?.[0]?.message ?? error.message}</span></div>` : nothing}\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${t('button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${!this.name.trim() || pending} @click=${() => this.submit()}>${t('button.save')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private async submit() {\n const fields = { name: this.name.trim(), category: this.category, description: this.description.trim() || null }\n const done = this.course.id ? (await this.change.run({ id: this.course.id, patch: fields }))?.updateCourse : (await this.save.run({ course: fields }))?.createCourse\n if (done) this.dispatchEvent(new CustomEvent('saved', { detail: done }))\n }\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import '@material/web/button/text-button.js';
3
+ import '@material/web/icon/icon.js';
4
+ import '@operato/input/ox-input-select-buttons.js';
5
+ import '@operato/popup/ox-popup-actions.js';
6
+ import { LitElement } from 'lit';
7
+ export type QuestionDraft = {
8
+ id?: string;
9
+ kind: string;
10
+ text: string;
11
+ explanation?: string | null;
12
+ drafted?: boolean;
13
+ choices: {
14
+ id?: string;
15
+ text: string;
16
+ correct: boolean;
17
+ }[];
18
+ };
19
+ /** Opens the question form. Resolves with the question as given, or null. */
20
+ export declare function openQuestionForm(question: QuestionDraft): Promise<QuestionDraft | null>;
21
+ declare const LearningQuestionForm_base: (new (...args: any[]) => LitElement) & typeof LitElement;
22
+ export declare class LearningQuestionForm extends LearningQuestionForm_base {
23
+ static styles: import("lit").CSSResult[];
24
+ question: QuestionDraft;
25
+ private draft;
26
+ willUpdate(changed: Map<string, unknown>): void;
27
+ render(): import("lit-html").TemplateResult<1>;
28
+ private kind;
29
+ private mark;
30
+ private write;
31
+ private removeChoice;
32
+ }
33
+ export {};
@@ -0,0 +1,142 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/button/filled-button.js';
3
+ import '@material/web/button/text-button.js';
4
+ import '@material/web/icon/icon.js';
5
+ import '@operato/input/ox-input-select-buttons.js';
6
+ import '@operato/popup/ox-popup-actions.js';
7
+ import { css, html, LitElement } from 'lit';
8
+ import { customElement, property, state } from 'lit/decorators.js';
9
+ import { i18next, localize } from '@operato/i18n';
10
+ import { openPopup } from '@operato/layout';
11
+ import { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles';
12
+ import { QUESTION_KINDS, questionKindWord, t } from '../utils/learning-words.js';
13
+ /** Opens the question form. Resolves with the question as given, or null. */
14
+ export function openQuestionForm(question) {
15
+ const popup = openPopup(html `<learning-question-form .question=${question} @done=${(e) => popup.close(e.detail)} @close=${() => popup.close()}></learning-question-form>`, { backdrop: true, size: 'large', title: question.id ? t('title.learning-question-edit') : t('title.learning-question-new') });
16
+ return popup.result.then(value => (value ?? null));
17
+ }
18
+ /* 문항 (ADR-0194 decision 4) - how it is answered, what it asks, its choices with which are right, and why. */
19
+ let LearningQuestionForm = class LearningQuestionForm extends localize(i18next)(LitElement) {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.question = { kind: 'SINGLE', text: '', choices: [] };
23
+ this.draft = { kind: 'SINGLE', text: '', choices: [] };
24
+ }
25
+ static { this.styles = [
26
+ CommonPopupStyles,
27
+ PopupBodyStyles,
28
+ FormFieldStyles,
29
+ PopupFieldStyles,
30
+ css `
31
+ ox-input-select-buttons {
32
+ align-self: flex-start;
33
+ }
34
+ textarea {
35
+ min-height: 80px;
36
+ resize: vertical;
37
+ }
38
+ .choice {
39
+ display: flex;
40
+ align-items: center;
41
+ gap: var(--spacing-small, 4px);
42
+ }
43
+ .choice input[type='text'] {
44
+ flex: 1;
45
+ }
46
+ .field .choice input[type='checkbox'],
47
+ .field .choice input[type='radio'] {
48
+ width: auto;
49
+ margin: 0;
50
+ }
51
+ .choice button {
52
+ border: 0;
53
+ background: transparent;
54
+ cursor: pointer;
55
+ color: var(--ui-muted);
56
+ padding: 4px;
57
+ }
58
+ `
59
+ ]; }
60
+ willUpdate(changed) {
61
+ if (changed.has('question')) {
62
+ const choices = this.question.choices?.length ? this.question.choices.map(one => ({ ...one })) : [{ text: '', correct: true }, { text: '', correct: false }];
63
+ this.draft = { ...this.question, choices };
64
+ }
65
+ }
66
+ render() {
67
+ const multiple = this.draft.kind === 'MULTIPLE';
68
+ const right = this.draft.choices.filter(one => one.correct).length;
69
+ const ready = this.draft.text.trim() && this.draft.choices.length >= 2 && this.draft.choices.every(one => one.text.trim()) && right >= 1 && (multiple || right === 1);
70
+ return html `
71
+ <div class="body">
72
+ <div class="field">
73
+ <span>${t('field.learning-question-kind')}</span>
74
+ <ox-input-select-buttons .value=${this.draft.kind} .options=${QUESTION_KINDS.map(code => ({ display: questionKindWord(code), value: code }))} @change=${(e) => e.detail && this.kind(e.detail)}></ox-input-select-buttons>
75
+ </div>
76
+ <label class="field">
77
+ <span>${t('field.learning-question-text')}</span>
78
+ <textarea .value=${this.draft.text} @input=${(e) => (this.draft = { ...this.draft, text: e.target.value })}></textarea>
79
+ </label>
80
+ <fieldset class="field" style="border:0;padding:0;margin:0">
81
+ <legend><span>${t('field.learning-question-choices')}</span></legend>
82
+ ${this.draft.choices.map((choice, index) => html `<div class="choice">
83
+ <input
84
+ type=${multiple ? 'checkbox' : 'radio'}
85
+ name="correct"
86
+ aria-label=${t('label.learning-choice-correct', { number: index + 1 })}
87
+ .checked=${choice.correct}
88
+ @change=${(e) => this.mark(index, e.target.checked)}
89
+ />
90
+ <input type="text" aria-label=${t('label.learning-choice-text', { number: index + 1 })} .value=${choice.text} ?readonly=${this.draft.kind === 'TRUE_FALSE'} @input=${(e) => this.write(index, e.target.value)} />
91
+ ${this.draft.kind !== 'TRUE_FALSE' && this.draft.choices.length > 2
92
+ ? html `<button aria-label=${t('button.learning-choice-remove')} @click=${() => this.removeChoice(index)}><md-icon>close</md-icon></button>`
93
+ : ''}
94
+ </div>`)}
95
+ ${this.draft.kind !== 'TRUE_FALSE'
96
+ ? html `<md-text-button style="align-self:flex-start" @click=${() => (this.draft = { ...this.draft, choices: [...this.draft.choices, { text: '', correct: false }] })}>${t('button.learning-choice-add')}</md-text-button>`
97
+ : ''}
98
+ <span>${multiple ? t('text.learning-question-multiple-hint') : t('text.learning-question-single-hint')}</span>
99
+ </fieldset>
100
+ <label class="field">
101
+ <span>${t('field.learning-question-explanation')}</span>
102
+ <textarea .value=${this.draft.explanation ?? ''} @input=${(e) => (this.draft = { ...this.draft, explanation: e.target.value })}></textarea>
103
+ </label>
104
+ </div>
105
+ <ox-popup-actions>
106
+ <md-text-button slot="cancel" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${t('button.cancel')}</md-text-button>
107
+ <md-filled-button slot="confirm" ?disabled=${!ready} @click=${() => this.dispatchEvent(new CustomEvent('done', { detail: this.draft }))}>${t('button.confirm')}</md-filled-button>
108
+ </ox-popup-actions>
109
+ `;
110
+ }
111
+ kind(kind) {
112
+ if (kind === 'TRUE_FALSE')
113
+ this.draft = { ...this.draft, kind, choices: [{ text: t('text.quiz-true'), correct: true }, { text: t('text.quiz-false'), correct: false }] };
114
+ else if (kind === 'SINGLE' && this.draft.choices.filter(one => one.correct).length > 1)
115
+ this.draft = { ...this.draft, kind, choices: this.draft.choices.map((one, i) => ({ ...one, correct: i === this.draft.choices.findIndex(c => c.correct) })) };
116
+ else
117
+ this.draft = { ...this.draft, kind };
118
+ }
119
+ mark(index, checked) {
120
+ const multiple = this.draft.kind === 'MULTIPLE';
121
+ this.draft = { ...this.draft, choices: this.draft.choices.map((one, i) => ({ ...one, correct: i === index ? checked : multiple ? one.correct : false })) };
122
+ }
123
+ write(index, text) {
124
+ this.draft = { ...this.draft, choices: this.draft.choices.map((one, i) => (i === index ? { ...one, text } : one)) };
125
+ }
126
+ removeChoice(index) {
127
+ this.draft = { ...this.draft, choices: this.draft.choices.filter((_, i) => i !== index) };
128
+ }
129
+ };
130
+ __decorate([
131
+ property({ attribute: false }),
132
+ __metadata("design:type", Object)
133
+ ], LearningQuestionForm.prototype, "question", void 0);
134
+ __decorate([
135
+ state(),
136
+ __metadata("design:type", Object)
137
+ ], LearningQuestionForm.prototype, "draft", void 0);
138
+ LearningQuestionForm = __decorate([
139
+ customElement('learning-question-form')
140
+ ], LearningQuestionForm);
141
+ export { LearningQuestionForm };
142
+ //# sourceMappingURL=learning-question-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-question-form.js","sourceRoot":"","sources":["../../client/components/learning-question-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles'\n\nimport { QUESTION_KINDS, questionKindWord, t } from '../utils/learning-words.js'\n\nexport type QuestionDraft = { id?: string; kind: string; text: string; explanation?: string | null; drafted?: boolean; choices: { id?: string; text: string; correct: boolean }[] }\n\n/** Opens the question form. Resolves with the question as given, or null. */\nexport function openQuestionForm(question: QuestionDraft): Promise<QuestionDraft | null> {\n const popup = openPopup(html`<learning-question-form .question=${question} @done=${(e: CustomEvent) => popup.close(e.detail)} @close=${() => popup.close()}></learning-question-form>`, { backdrop: true, size: 'large', title: question.id ? t('title.learning-question-edit') : t('title.learning-question-new') })\n return popup.result.then(value => (value ?? null) as any)\n}\n\n/* 문항 (ADR-0194 decision 4) - how it is answered, what it asks, its choices with which are right, and why. */\n@customElement('learning-question-form')\nexport class LearningQuestionForm extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n FormFieldStyles,\n PopupFieldStyles,\n css`\n ox-input-select-buttons {\n align-self: flex-start;\n }\n textarea {\n min-height: 80px;\n resize: vertical;\n }\n .choice {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n }\n .choice input[type='text'] {\n flex: 1;\n }\n .field .choice input[type='checkbox'],\n .field .choice input[type='radio'] {\n width: auto;\n margin: 0;\n }\n .choice button {\n border: 0;\n background: transparent;\n cursor: pointer;\n color: var(--ui-muted);\n padding: 4px;\n }\n `\n ]\n\n @property({ attribute: false }) question: QuestionDraft = { kind: 'SINGLE', text: '', choices: [] }\n @state() private draft: QuestionDraft = { kind: 'SINGLE', text: '', choices: [] }\n\n willUpdate(changed: Map<string, unknown>) {\n if (changed.has('question')) {\n const choices = this.question.choices?.length ? this.question.choices.map(one => ({ ...one })) : [{ text: '', correct: true }, { text: '', correct: false }]\n this.draft = { ...this.question, choices }\n }\n }\n\n render() {\n const multiple = this.draft.kind === 'MULTIPLE'\n const right = this.draft.choices.filter(one => one.correct).length\n const ready = this.draft.text.trim() && this.draft.choices.length >= 2 && this.draft.choices.every(one => one.text.trim()) && right >= 1 && (multiple || right === 1)\n return html`\n <div class=\"body\">\n <div class=\"field\">\n <span>${t('field.learning-question-kind')}</span>\n <ox-input-select-buttons .value=${this.draft.kind} .options=${QUESTION_KINDS.map(code => ({ display: questionKindWord(code), value: code }))} @change=${(e: CustomEvent) => e.detail && this.kind(e.detail)}></ox-input-select-buttons>\n </div>\n <label class=\"field\">\n <span>${t('field.learning-question-text')}</span>\n <textarea .value=${this.draft.text} @input=${(e: any) => (this.draft = { ...this.draft, text: e.target.value })}></textarea>\n </label>\n <fieldset class=\"field\" style=\"border:0;padding:0;margin:0\">\n <legend><span>${t('field.learning-question-choices')}</span></legend>\n ${this.draft.choices.map(\n (choice, index) => html`<div class=\"choice\">\n <input\n type=${multiple ? 'checkbox' : 'radio'}\n name=\"correct\"\n aria-label=${t('label.learning-choice-correct', { number: index + 1 })}\n .checked=${choice.correct}\n @change=${(e: any) => this.mark(index, e.target.checked)}\n />\n <input type=\"text\" aria-label=${t('label.learning-choice-text', { number: index + 1 })} .value=${choice.text} ?readonly=${this.draft.kind === 'TRUE_FALSE'} @input=${(e: any) => this.write(index, e.target.value)} />\n ${this.draft.kind !== 'TRUE_FALSE' && this.draft.choices.length > 2\n ? html`<button aria-label=${t('button.learning-choice-remove')} @click=${() => this.removeChoice(index)}><md-icon>close</md-icon></button>`\n : ''}\n </div>`\n )}\n ${this.draft.kind !== 'TRUE_FALSE'\n ? html`<md-text-button style=\"align-self:flex-start\" @click=${() => (this.draft = { ...this.draft, choices: [...this.draft.choices, { text: '', correct: false }] })}>${t('button.learning-choice-add')}</md-text-button>`\n : ''}\n <span>${multiple ? t('text.learning-question-multiple-hint') : t('text.learning-question-single-hint')}</span>\n </fieldset>\n <label class=\"field\">\n <span>${t('field.learning-question-explanation')}</span>\n <textarea .value=${this.draft.explanation ?? ''} @input=${(e: any) => (this.draft = { ...this.draft, explanation: e.target.value })}></textarea>\n </label>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${t('button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${!ready} @click=${() => this.dispatchEvent(new CustomEvent('done', { detail: this.draft }))}>${t('button.confirm')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private kind(kind: string) {\n if (kind === 'TRUE_FALSE')\n this.draft = { ...this.draft, kind, choices: [{ text: t('text.quiz-true'), correct: true }, { text: t('text.quiz-false'), correct: false }] }\n else if (kind === 'SINGLE' && this.draft.choices.filter(one => one.correct).length > 1)\n this.draft = { ...this.draft, kind, choices: this.draft.choices.map((one, i) => ({ ...one, correct: i === this.draft.choices.findIndex(c => c.correct) })) }\n else this.draft = { ...this.draft, kind }\n }\n\n private mark(index: number, checked: boolean) {\n const multiple = this.draft.kind === 'MULTIPLE'\n this.draft = { ...this.draft, choices: this.draft.choices.map((one, i) => ({ ...one, correct: i === index ? checked : multiple ? one.correct : false })) }\n }\n\n private write(index: number, text: string) {\n this.draft = { ...this.draft, choices: this.draft.choices.map((one, i) => (i === index ? { ...one, text } : one)) }\n }\n\n private removeChoice(index: number) {\n this.draft = { ...this.draft, choices: this.draft.choices.filter((_, i) => i !== index) }\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import { LitElement } from 'lit';
3
+ declare const LearningTodo_base: (new (...args: any[]) => LitElement) & typeof LitElement;
4
+ export declare class LearningTodo extends LearningTodo_base {
5
+ static styles: import("lit").CSSResult;
6
+ input: {
7
+ headline?: string;
8
+ address?: string;
9
+ };
10
+ render(): import("lit-html").TemplateResult<1>;
11
+ }
12
+ export {};
@@ -0,0 +1,43 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/button/filled-button.js';
3
+ import { css, html, LitElement } from 'lit';
4
+ import { customElement, property } from 'lit/decorators.js';
5
+ import { i18next, localize } from '@operato/i18n';
6
+ import { navigate } from '@operato/shell';
7
+ /*
8
+ * 수강 (ADR-0194 decision 5) - what the worklist to-do shows: the course, by when, and the way to it. Completing the
9
+ * course there ends the to-do; nothing is answered here.
10
+ */
11
+ let LearningTodo = class LearningTodo extends localize(i18next)(LitElement) {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.input = {};
15
+ }
16
+ static { this.styles = css `
17
+ :host {
18
+ display: block;
19
+ padding: var(--spacing-large, 12px);
20
+ font-size: var(--ui-t-body, 13px);
21
+ line-height: 1.6;
22
+ color: var(--ui-ink);
23
+ }
24
+
25
+ p {
26
+ margin: 0 0 var(--spacing-medium, 8px);
27
+ }
28
+ `; }
29
+ render() {
30
+ const { headline = '', address } = this.input ?? {};
31
+ return html `<p>${headline}</p>
32
+ ${address ? html `<md-filled-button @click=${() => navigate(address)}>${i18next.t('button.learning-open-course')}</md-filled-button>` : ''}`;
33
+ }
34
+ };
35
+ __decorate([
36
+ property({ attribute: false }),
37
+ __metadata("design:type", Object)
38
+ ], LearningTodo.prototype, "input", void 0);
39
+ LearningTodo = __decorate([
40
+ customElement('learning-todo')
41
+ ], LearningTodo);
42
+ export { LearningTodo };
43
+ //# sourceMappingURL=learning-todo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-todo.js","sourceRoot":"","sources":["../../client/components/learning-todo.ts"],"names":[],"mappings":";AAAA,OAAO,uCAAuC,CAAA;AAE9C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC;;;GAGG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAxD;;QAe2B,UAAK,GAA4C,EAAE,CAAA;IAOrF,CAAC;aArBQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;GAYlB,AAZY,CAYZ;IAID,MAAM;QACJ,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;QACnD,OAAO,IAAI,CAAA,MAAM,QAAQ;QACrB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,4BAA4B,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IAC/I,CAAC;;AAN+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;2CAAoD;AAfxE,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAsBxB","sourcesContent":["import '@material/web/button/filled-button.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate } from '@operato/shell'\n\n/*\n * 수강 (ADR-0194 decision 5) - what the worklist to-do shows: the course, by when, and the way to it. Completing the\n * course there ends the to-do; nothing is answered here.\n */\n@customElement('learning-todo')\nexport class LearningTodo extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n padding: var(--spacing-large, 12px);\n font-size: var(--ui-t-body, 13px);\n line-height: 1.6;\n color: var(--ui-ink);\n }\n\n p {\n margin: 0 0 var(--spacing-medium, 8px);\n }\n `\n\n @property({ attribute: false }) input: { headline?: string; address?: string } = {}\n\n render() {\n const { headline = '', address } = this.input ?? {}\n return html`<p>${headline}</p>\n ${address ? html`<md-filled-button @click=${() => navigate(address)}>${i18next.t('button.learning-open-course')}</md-filled-button>` : ''}`\n }\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import '@material/web/button/text-button.js';
3
+ import '@operato/input/ox-input-file.js';
4
+ import '@operato/input/ox-input-select-buttons.js';
5
+ import '@operato/popup/ox-popup-actions.js';
6
+ import { LitElement } from 'lit';
7
+ export type UnitDraft = {
8
+ id?: string;
9
+ kind: string;
10
+ name: string;
11
+ body?: string | null;
12
+ url?: string | null;
13
+ minSeconds?: number | null;
14
+ durationSeconds?: number | null;
15
+ file?: {
16
+ name?: string;
17
+ } | null;
18
+ };
19
+ export type UnitEdit = {
20
+ unit: UnitDraft;
21
+ file?: File;
22
+ durationSeconds?: number;
23
+ };
24
+ /** Opens the unit form. Resolves with what was given - the unit and a file picked for it - or null. */
25
+ export declare function openUnitForm(unit: UnitDraft): Promise<UnitEdit | null>;
26
+ /** A video's length in seconds, read from the file in the browser - the server needs it to know when it was watched to the end. */
27
+ export declare function videoDurationOf(file: File): Promise<number | undefined>;
28
+ declare const LearningUnitForm_base: (new (...args: any[]) => LitElement) & typeof LitElement;
29
+ export declare class LearningUnitForm extends LearningUnitForm_base {
30
+ static styles: import("lit").CSSResult[];
31
+ unit: UnitDraft;
32
+ private draft;
33
+ private file?;
34
+ private duration?;
35
+ willUpdate(changed: Map<string, unknown>): void;
36
+ render(): import("lit-html").TemplateResult<1>;
37
+ private patch;
38
+ private pick;
39
+ private done;
40
+ }
41
+ export {};