@vue-skuilder/edit-ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index.css +1 -0
- package/dist/edit-ui.es.js +71090 -0
- package/dist/edit-ui.es.js.map +1 -0
- package/dist/edit-ui.umd.js +83 -0
- package/dist/edit-ui.umd.js.map +1 -0
- package/package.json +67 -0
- package/src/components/BulkImport/CardPreviewList.vue +345 -0
- package/src/components/BulkImportView.vue +633 -0
- package/src/components/CourseEditor.vue +164 -0
- package/src/components/ViewableDataInputForm/DataInputForm.vue +533 -0
- package/src/components/ViewableDataInputForm/FieldInput.types.ts +33 -0
- package/src/components/ViewableDataInputForm/FieldInputs/AudioInput.vue +188 -0
- package/src/components/ViewableDataInputForm/FieldInputs/ChessPuzzleInput.vue +79 -0
- package/src/components/ViewableDataInputForm/FieldInputs/FieldInput.css +12 -0
- package/src/components/ViewableDataInputForm/FieldInputs/ImageInput.vue +231 -0
- package/src/components/ViewableDataInputForm/FieldInputs/IntegerInput.vue +49 -0
- package/src/components/ViewableDataInputForm/FieldInputs/MarkdownInput.vue +34 -0
- package/src/components/ViewableDataInputForm/FieldInputs/MediaDragDropUploader.vue +246 -0
- package/src/components/ViewableDataInputForm/FieldInputs/MidiInput.vue +113 -0
- package/src/components/ViewableDataInputForm/FieldInputs/NumberInput.vue +49 -0
- package/src/components/ViewableDataInputForm/FieldInputs/OptionsFieldInput.ts +161 -0
- package/src/components/ViewableDataInputForm/FieldInputs/StringInput.vue +49 -0
- package/src/components/ViewableDataInputForm/FieldInputs/typeValidators.ts +49 -0
- package/src/components/index.ts +21 -0
- package/src/index.ts +6 -0
- package/src/stores/useDataInputFormStore.ts +49 -0
- package/src/stores/useFieldInputStore.ts +191 -0
- package/src/vue-shims.d.ts +5 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { DataShape } from '@vue-skuilder/common';
|
|
3
|
+
import { CourseConfig } from '@vue-skuilder/common';
|
|
4
|
+
import { FieldInputInstance } from '../components/ViewableDataInputForm/FieldInput.types';
|
|
5
|
+
import { useFieldInputStore } from './useFieldInputStore';
|
|
6
|
+
import { ViewComponent } from '@vue-skuilder/common-ui';
|
|
7
|
+
|
|
8
|
+
interface DataInputForm {
|
|
9
|
+
// current props
|
|
10
|
+
dataShape: DataShape | null;
|
|
11
|
+
course: CourseConfig | null;
|
|
12
|
+
|
|
13
|
+
shapeViews: ViewComponent[];
|
|
14
|
+
fields: FieldInputInstance[];
|
|
15
|
+
|
|
16
|
+
fieldStore: ReturnType<typeof useFieldInputStore>;
|
|
17
|
+
|
|
18
|
+
uploading: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface DataInputFormState {
|
|
22
|
+
dataInputForm: DataInputForm;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const useDataInputFormStore = defineStore('dataInputForm', {
|
|
26
|
+
state: (): DataInputFormState => ({
|
|
27
|
+
dataInputForm: {
|
|
28
|
+
dataShape: null,
|
|
29
|
+
course: null,
|
|
30
|
+
shapeViews: [],
|
|
31
|
+
|
|
32
|
+
fields: [],
|
|
33
|
+
fieldStore: useFieldInputStore(),
|
|
34
|
+
uploading: false,
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
// actions or getters if needed
|
|
38
|
+
actions: {
|
|
39
|
+
setDataShape(ds: DataShape) {
|
|
40
|
+
this.dataInputForm.dataShape = ds;
|
|
41
|
+
this.dataInputForm.fieldStore.dataShape = ds;
|
|
42
|
+
this.dataInputForm.fieldStore.$reset();
|
|
43
|
+
},
|
|
44
|
+
setCourse(course: CourseConfig) {
|
|
45
|
+
this.dataInputForm.course = course;
|
|
46
|
+
},
|
|
47
|
+
// etc. create any convenience setters or methods you wish
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { DataShape, FieldType, Status, fieldConverters } from '@vue-skuilder/common';
|
|
2
|
+
import { defineStore } from 'pinia';
|
|
3
|
+
|
|
4
|
+
export interface MediaInputs {
|
|
5
|
+
[key: `audio-${number}`]: unknown;
|
|
6
|
+
[key: `image-${number}`]: unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface FieldInputStore {
|
|
10
|
+
// [key: string]: unknown;
|
|
11
|
+
|
|
12
|
+
// // Raw field values by field name
|
|
13
|
+
//
|
|
14
|
+
//
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The
|
|
18
|
+
*/
|
|
19
|
+
dataShape: DataShape | null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Raw input field values by field name - the user-edited submissions
|
|
23
|
+
*/
|
|
24
|
+
inputs: Record<string, unknown>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* additions from the MediaDragDrop editor.
|
|
28
|
+
*/
|
|
29
|
+
mediaInputs: MediaInputs;
|
|
30
|
+
|
|
31
|
+
inputIsValid: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validation status of each field - all must be true for the form to be valid and the data to be submissable
|
|
35
|
+
*/
|
|
36
|
+
validation: Record<string, boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Input prepared for sending to the database
|
|
39
|
+
*/
|
|
40
|
+
convertedInput: Record<string, unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Input prepared for local rendering in a preview
|
|
43
|
+
*/
|
|
44
|
+
previewInput: Record<string, unknown>;
|
|
45
|
+
|
|
46
|
+
// getFieldValue(fieldName: string): unknown;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const useFieldInputStore = defineStore('fieldStore', {
|
|
50
|
+
state: (): FieldInputStore => ({
|
|
51
|
+
dataShape: null as DataShape | null,
|
|
52
|
+
inputs: {},
|
|
53
|
+
mediaInputs: {} as MediaInputs,
|
|
54
|
+
inputIsValid: false,
|
|
55
|
+
|
|
56
|
+
validation: {},
|
|
57
|
+
convertedInput: {},
|
|
58
|
+
previewInput: {},
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
getters: {
|
|
62
|
+
isValidated(): boolean {
|
|
63
|
+
return this.inputIsValid;
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
getPreview: (state) => {
|
|
67
|
+
if (state.inputIsValid) return state.previewInput;
|
|
68
|
+
else return {};
|
|
69
|
+
},
|
|
70
|
+
getConverted: (state) => {
|
|
71
|
+
if (state.inputIsValid) return state.convertedInput;
|
|
72
|
+
else return {};
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
actions: {
|
|
77
|
+
$reset() {
|
|
78
|
+
console.log(`[FieldInputStore].reset()`);
|
|
79
|
+
this.inputs = {};
|
|
80
|
+
this.mediaInputs = {};
|
|
81
|
+
this.validation = {};
|
|
82
|
+
this.convertedInput = {};
|
|
83
|
+
this.previewInput = {};
|
|
84
|
+
this.inputIsValid = false;
|
|
85
|
+
|
|
86
|
+
// Clear all media entries
|
|
87
|
+
const MAX_MEDIA_INPUTS = 10;
|
|
88
|
+
for (let i = 1; i <= MAX_MEDIA_INPUTS; i++) {
|
|
89
|
+
const audioKey = `audio-${i}` as keyof MediaInputs;
|
|
90
|
+
const imageKey = `image-${i}` as keyof MediaInputs;
|
|
91
|
+
|
|
92
|
+
delete this.mediaInputs[audioKey];
|
|
93
|
+
delete this.mediaInputs[imageKey];
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
setFieldValue(fieldName: string, value: unknown) {
|
|
98
|
+
this.inputs[fieldName] = value;
|
|
99
|
+
this.validate();
|
|
100
|
+
this.convert();
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
setMedia(
|
|
104
|
+
fieldName: keyof MediaInputs,
|
|
105
|
+
media: {
|
|
106
|
+
content_type: string;
|
|
107
|
+
data: Blob;
|
|
108
|
+
}
|
|
109
|
+
) {
|
|
110
|
+
console.log(`[FieldInputStore].setMedia: ${fieldName}`);
|
|
111
|
+
this.mediaInputs[fieldName] = media;
|
|
112
|
+
this.convert();
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
validate() {
|
|
116
|
+
this.validation = {};
|
|
117
|
+
|
|
118
|
+
if (this.dataShape === null) {
|
|
119
|
+
this.inputIsValid = false;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.inputIsValid = true;
|
|
124
|
+
|
|
125
|
+
for (const field of this.dataShape.fields) {
|
|
126
|
+
if (field.validator) {
|
|
127
|
+
const result = field.validator.test(this.inputs[field.name] as unknown as string);
|
|
128
|
+
if (result.status === Status.ok) {
|
|
129
|
+
this.validation[field.name] = true;
|
|
130
|
+
} else {
|
|
131
|
+
this.inputIsValid = false;
|
|
132
|
+
this.validation[field.name] = false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
convert() {
|
|
139
|
+
this.convertedInput = {};
|
|
140
|
+
|
|
141
|
+
this.dataShape?.fields.forEach((f) => {
|
|
142
|
+
this.convertedInput[f.name] = fieldConverters[f.type].databaseConverter(
|
|
143
|
+
this.inputs[f.name]
|
|
144
|
+
);
|
|
145
|
+
this.previewInput[f.name] = fieldConverters[f.type].previewConverter(this.inputs[f.name]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Check for media entries
|
|
149
|
+
for (let i = 1; i < 11; i++) {
|
|
150
|
+
const index = `audio-${i}` as keyof MediaInputs;
|
|
151
|
+
const value = this.mediaInputs[index];
|
|
152
|
+
if (value) {
|
|
153
|
+
this.convertedInput[index] = fieldConverters[FieldType.AUDIO].databaseConverter(value);
|
|
154
|
+
this.previewInput[index] = fieldConverters[FieldType.AUDIO].previewConverter(value);
|
|
155
|
+
} else {
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
for (let i = 1; i < 11; i++) {
|
|
161
|
+
const index = `image-${i}` as keyof MediaInputs;
|
|
162
|
+
const value = this.mediaInputs[index];
|
|
163
|
+
if (value) {
|
|
164
|
+
this.convertedInput[index] = fieldConverters[FieldType.IMAGE].databaseConverter(value);
|
|
165
|
+
this.previewInput[index] = fieldConverters[FieldType.IMAGE].previewConverter(value);
|
|
166
|
+
} else {
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
clearMediaEntries() {
|
|
173
|
+
// Clear all media entries up to a reasonable limit
|
|
174
|
+
for (let i = 1; i <= 10; i++) {
|
|
175
|
+
delete this.mediaInputs[`audio-${i}`];
|
|
176
|
+
delete this.mediaInputs[`image-${i}`];
|
|
177
|
+
delete this.convertedInput[`audio-${i}`];
|
|
178
|
+
delete this.convertedInput[`image-${i}`];
|
|
179
|
+
delete this.previewInput[`audio-${i}`];
|
|
180
|
+
delete this.previewInput[`image-${i}`];
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
clearField(fieldName: string) {
|
|
185
|
+
delete this.inputs[fieldName];
|
|
186
|
+
delete this.validation[fieldName];
|
|
187
|
+
delete this.convertedInput[fieldName];
|
|
188
|
+
delete this.previewInput[fieldName];
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
});
|