feat(components): make story creation/editing components
This commit is contained in:
		
							parent
							
								
									52f5b4a811
								
							
						
					
					
						commit
						b2e950e798
					
				
							
								
								
									
										54
									
								
								components/story/atoms/bands.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								components/story/atoms/bands.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | 	import { DefaultOptionType } from "ant-design-vue/es/select"; | ||||||
|  | 	import { RuleExpression, useField } from "vee-validate"; | ||||||
|  | 	import { cs } from "~/lib/client/storyFormSchema"; | ||||||
|  | 	import { IBand } from "~/models/band"; | ||||||
|  | 	import { log } from "~/lib/server/logger"; | ||||||
|  | 
 | ||||||
|  | 	import iconEl from "../icon.vue"; | ||||||
|  | 
 | ||||||
|  | 	const bandlist = inject<IBand[]>("bandlist"); | ||||||
|  | 	const fname = inject<string>("curName"); | ||||||
|  | 	const { updateBands, sb } = inject<any>("selectedBands"); | ||||||
|  | 
 | ||||||
|  | 	const bl = ref(bandlist || []); | ||||||
|  | 	const options: DefaultOptionType[] = bl.value | ||||||
|  | 		.filter((a) => a.name != "") | ||||||
|  | 		.map((a) => ({ | ||||||
|  | 			value: a._id, | ||||||
|  | 			label: a.name, | ||||||
|  | 			disabled: a.locked || false, | ||||||
|  | 		})); | ||||||
|  | 	let bandField = useField( | ||||||
|  | 		fname + "bands", | ||||||
|  | 		cs.fields.bands as unknown as MaybeRef<RuleExpression<number[]>>, | ||||||
|  | 	); | ||||||
|  | 	const { value, errorMessage, name, setValue } = bandField; | ||||||
|  | 	// setValue(sb) | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  | 	<a-form-item | ||||||
|  | 		:validate-status="!!errorMessage ? 'error' : undefined" | ||||||
|  | 		:help="errorMessage" | ||||||
|  | 		label="Bands" | ||||||
|  | 	> | ||||||
|  | 		<a-select | ||||||
|  | 			:allow-clear="true" | ||||||
|  | 			mode="multiple" | ||||||
|  | 			@change=" | ||||||
|  | 				(val) => { | ||||||
|  | 					// log.debug(val); | ||||||
|  | 					updateBands(val); | ||||||
|  | 					setValue(val as number[]); | ||||||
|  | 				} | ||||||
|  | 			" | ||||||
|  | 			v-model:value="value" | ||||||
|  | 			:options="options" | ||||||
|  | 		> | ||||||
|  | 			<template #removeIcon> | ||||||
|  | 				<i class="far fa-circle-x" /> | ||||||
|  | 			</template> | ||||||
|  | 		</a-select> | ||||||
|  | 	</a-form-item> | ||||||
|  | </template> | ||||||
							
								
								
									
										35
									
								
								components/story/atoms/characters.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								components/story/atoms/characters.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | 	import { RuleExpression, useField } from "vee-validate"; | ||||||
|  | 	import { cs } from "~/lib/client/storyFormSchema"; | ||||||
|  | 	import { IBand } from "~/models/band"; | ||||||
|  | 	const fname = inject<string>("curName"); | ||||||
|  | 	const { sb: selectedBands } = inject<any>("selectedBands"); | ||||||
|  | 	const allBands = inject<Ref<IBand[]>>("bandlist"); | ||||||
|  | 	const opts = computed(() => { | ||||||
|  | 		const unflattened: any[] = []; | ||||||
|  | 		selectedBands?.value?.forEach((v: number) => { | ||||||
|  | 			unflattened.push(allBands?.value.find((a) => a._id == v)?.characters); | ||||||
|  | 		}); | ||||||
|  | 		return unflattened.flat(Infinity).map((a) => ({ value: a, label: a })); | ||||||
|  | 	}); | ||||||
|  | 	const charField = useField<string[]>( | ||||||
|  | 		fname + "characters", | ||||||
|  | 		cs.fields.characters as unknown as MaybeRef<RuleExpression<string[]>>, | ||||||
|  | 	); | ||||||
|  | 	const { value, errorMessage, name: bandName, setValue } = charField; | ||||||
|  | 	// setValue([]); | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  | 	<a-form-item | ||||||
|  | 		:help="errorMessage" | ||||||
|  | 		label="Characters" | ||||||
|  | 		:name="bandName as string" | ||||||
|  | 		:validate-status="!!errorMessage ? 'error' : undefined" | ||||||
|  | 	> | ||||||
|  | 		<a-select mode="multiple" :options="opts" v-model:value="value"> | ||||||
|  | 			<template #removeIcon> | ||||||
|  | 				<i class="far fa-circle-x" /> | ||||||
|  | 			</template> | ||||||
|  | 		</a-select> | ||||||
|  | 	</a-form-item> | ||||||
|  | </template> | ||||||
							
								
								
									
										28
									
								
								components/story/atoms/genre.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								components/story/atoms/genre.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | <script lang="ts" setup> | ||||||
|  | 	import { useField } from "vee-validate"; | ||||||
|  | 	const fname = inject<string>("curName"); | ||||||
|  | 	let data = await useApiFetch("/genres"); | ||||||
|  | 	let opts = (data.data.value as unknown as any[]).map((a) => ({ | ||||||
|  | 		value: a, | ||||||
|  | 		label: a, | ||||||
|  | 	})); | ||||||
|  | 	const { value, errorMessage, name, setValue } = useField(fname + "genre"); | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  | 	<a-form-item | ||||||
|  | 		:help="errorMessage" | ||||||
|  | 		label="Genre(s)" | ||||||
|  | 		:validate-status="!!errorMessage ? 'error' : undefined" | ||||||
|  | 	> | ||||||
|  | 		<a-select | ||||||
|  | 			:allow-clear="true" | ||||||
|  | 			:options="opts" | ||||||
|  | 			v-model:value="value as string[]" | ||||||
|  | 			mode="multiple" | ||||||
|  | 		> | ||||||
|  | 			<template #removeIcon> | ||||||
|  | 				<i class="far fa-circle-x" /> | ||||||
|  | 			</template> | ||||||
|  | 		</a-select> | ||||||
|  | 	</a-form-item> | ||||||
|  | </template> | ||||||
							
								
								
									
										50
									
								
								components/story/atoms/pairings.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								components/story/atoms/pairings.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | <script lang="ts" setup> | ||||||
|  | 	import { Field, useFieldArray } from "vee-validate"; | ||||||
|  | 	import { IBand } from "~/models/band"; | ||||||
|  | 
 | ||||||
|  | 	const { sb: selectedBands } = inject<any>("selectedBands"); | ||||||
|  | 	const allBands = inject<Ref<IBand[]>>("bandlist"); | ||||||
|  | 	const fname = inject<string>("curName"); | ||||||
|  | 	const opts = computed(() => { | ||||||
|  | 		const uf: any[] = []; | ||||||
|  | 		selectedBands.value.forEach((v: number) => { | ||||||
|  | 			uf.push(allBands?.value.find((a) => a._id == v)?.characters); | ||||||
|  | 		}); | ||||||
|  | 		return uf.flat(Infinity).map((a) => ({ value: a, label: a })); | ||||||
|  | 	}); | ||||||
|  | 	const { fields, push, remove, replace, update } = useFieldArray<string[]>( | ||||||
|  | 		fname + "relationships", | ||||||
|  | 	); | ||||||
|  | 	// replace([]); | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  | 	<a-form-item label="Pairings"> | ||||||
|  | 		<a-row | ||||||
|  | 			:gutter="5" | ||||||
|  | 			:wrap="true" | ||||||
|  | 			v-for="(field, idx) in fields" | ||||||
|  | 			:key="field.key" | ||||||
|  | 		> | ||||||
|  | 			<Field :name="fname + 'relationships' + `[${idx}]`"> | ||||||
|  | 				<a-select | ||||||
|  | 					mode="multiple" | ||||||
|  | 					:options="opts" | ||||||
|  | 					v-model:value="field.value as string[]" | ||||||
|  | 					@change="(val) => update(idx, val as string[])" | ||||||
|  | 				> | ||||||
|  | 					<template #removeIcon> | ||||||
|  | 						<i class="far fa-circle-x" /> | ||||||
|  | 					</template> | ||||||
|  | 				</a-select> | ||||||
|  | 			</Field> | ||||||
|  | 			<a-col :span="4"> | ||||||
|  | 				<a-button @click="(e) => remove(idx)"> - </a-button> | ||||||
|  | 			</a-col> | ||||||
|  | 		</a-row> | ||||||
|  | 		<a-row justify="end"> | ||||||
|  | 			<a-col :span="2"> | ||||||
|  | 				<a-button @click="(e) => push([])"> + </a-button> | ||||||
|  | 			</a-col> | ||||||
|  | 		</a-row> | ||||||
|  | 	</a-form-item> | ||||||
|  | </template> | ||||||
							
								
								
									
										17
									
								
								components/story/atoms/test1.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								components/story/atoms/test1.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <template> | ||||||
|  | 	<a-select | ||||||
|  | 		mode="multiple" | ||||||
|  | 		style="width: 100%" | ||||||
|  | 		placeholder="Please select" | ||||||
|  | 		:options=" | ||||||
|  | 			[...Array(25)].map((_, i) => ({ value: (i + 10).toString(36) + (i + 1) })) | ||||||
|  | 		" | ||||||
|  | 		@change="handleChange" | ||||||
|  | 	></a-select> | ||||||
|  | </template> | ||||||
|  | <script lang="ts" setup> | ||||||
|  | 	import { SelectValue } from "ant-design-vue/es/select"; | ||||||
|  | 	import { ref } from "vue"; | ||||||
|  | 	const handleChange = (value: SelectValue) => {}; | ||||||
|  | 	const value = ref(["a1", "b2"]); | ||||||
|  | </script> | ||||||
							
								
								
									
										135
									
								
								components/story/create/singleChapter.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								components/story/create/singleChapter.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | 	import { | ||||||
|  | 		Form as VeeForm, | ||||||
|  | 		Field, | ||||||
|  | 		useForm, | ||||||
|  | 		useField, | ||||||
|  | 		ErrorMessage, | ||||||
|  | 	} from "vee-validate"; | ||||||
|  | 	import { NamePath } from "ant-design-vue/es/form/interface"; | ||||||
|  | 	import { FormChapter } from "~/lib/client/types/form/story"; | ||||||
|  | 
 | ||||||
|  | 	import { story, bare } from "~/lib/client/editorConfig"; | ||||||
|  | 	import elBands from "../atoms/bands.vue"; | ||||||
|  | 	import genre from "../atoms/genre.vue"; | ||||||
|  | 	import elCharacters from "../atoms/characters.vue"; | ||||||
|  | 	import elPairings from "../atoms/pairings.vue"; | ||||||
|  | 	import uploadOrPaste from "./uploadOrPaste.vue"; | ||||||
|  | 	// import test1 from | ||||||
|  | 
 | ||||||
|  | 	let { name, data } = defineProps<{ | ||||||
|  | 		name: NamePath; | ||||||
|  | 		data: FormChapter; | ||||||
|  | 	}>(); | ||||||
|  | 	let acData = toRef(data); | ||||||
|  | 	let { data: _bands } = await useApiFetch("/bands/all"); | ||||||
|  | 	let bands = ref(_bands); | ||||||
|  | 	provide("curName", name + "."); | ||||||
|  | 	provide("bandlist", bands); | ||||||
|  | 	const selectedBands = ref(data.bands || []); | ||||||
|  | 	const updateBands = (val) => { | ||||||
|  | 		selectedBands.value = val; | ||||||
|  | 		// data.value.bands = val; | ||||||
|  | 	}; | ||||||
|  | 	provide("selectedBands", { | ||||||
|  | 		sb: selectedBands, | ||||||
|  | 		updateBands, | ||||||
|  | 	}); | ||||||
|  | 	const wrapc = { span: 12 }; | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  | 	<div> | ||||||
|  | 		<a-row :gutter="[10, 0]"> | ||||||
|  | 			<a-col :span="12"> | ||||||
|  | 				<Field | ||||||
|  | 					:name="name + '.chapterTitle'" | ||||||
|  | 					v-slot="{ value, field, errorMessage }" | ||||||
|  | 				> | ||||||
|  | 					<a-form-item | ||||||
|  | 						:name="[field.name]" | ||||||
|  | 						label="Chapter title" | ||||||
|  | 						:help="errorMessage" | ||||||
|  | 						:status="!!errorMessage ? 'error' : undefined" | ||||||
|  | 					> | ||||||
|  | 						<a-input v-bind="field" /> | ||||||
|  | 					</a-form-item> | ||||||
|  | 				</Field> | ||||||
|  | 			</a-col> | ||||||
|  | 			<a-col :span="12"> | ||||||
|  | 				<el-bands /> | ||||||
|  | 			</a-col> | ||||||
|  | 		</a-row> | ||||||
|  | 		<a-row :gutter="[10, 0]"> | ||||||
|  | 			<a-col :span="12"> | ||||||
|  | 				<base-editor | ||||||
|  | 					v-model:val="acData.summary" | ||||||
|  | 					:name="name + '.summary'" | ||||||
|  | 					:wrap-col="wrapc" | ||||||
|  | 					label="Summary" | ||||||
|  | 					:init="bare" | ||||||
|  | 				/> | ||||||
|  | 			</a-col> | ||||||
|  | 			<a-col :span="12"> | ||||||
|  | 				<base-editor | ||||||
|  | 					v-model:val="acData.notes" | ||||||
|  | 					:name="name + '.notes'" | ||||||
|  | 					:wrap-col="wrapc" | ||||||
|  | 					label="Author's notes" | ||||||
|  | 					:init="bare" | ||||||
|  | 				/> | ||||||
|  | 			</a-col> | ||||||
|  | 		</a-row> | ||||||
|  | 		<a-row :gutter="[10, 0]"> | ||||||
|  | 			<a-col :span="12"> | ||||||
|  | 				<el-characters /> | ||||||
|  | 			</a-col> | ||||||
|  | 			<a-col :span="12"> | ||||||
|  | 				<el-pairings /> | ||||||
|  | 			</a-col> | ||||||
|  | 		</a-row> | ||||||
|  | 		<Field | ||||||
|  | 			:name="name + '.nsfw'" | ||||||
|  | 			type="checkbox" | ||||||
|  | 			:unchecked-value="false" | ||||||
|  | 			:value="true" | ||||||
|  | 			v-slot="{ value, field, errorMessage }" | ||||||
|  | 		> | ||||||
|  | 			<a-checkbox v-bind="field" v-model="field.value"> | ||||||
|  | 				Has NSFW content | ||||||
|  | 			</a-checkbox> | ||||||
|  | 			<error-message :name="field.name" /> | ||||||
|  | 		</Field> | ||||||
|  | 		<Field | ||||||
|  | 			:name="name + '.loggedInOnly'" | ||||||
|  | 			type="checkbox" | ||||||
|  | 			:unchecked-value="false" | ||||||
|  | 			:value="true" | ||||||
|  | 			v-slot="{ value, field, errorMessage }" | ||||||
|  | 		> | ||||||
|  | 			<a-checkbox v-bind="field"> Visible only to registered users </a-checkbox> | ||||||
|  | 			<error-message :name="field.name" /> | ||||||
|  | 		</Field> | ||||||
|  | 		<Field | ||||||
|  | 			:name="name + '.hidden'" | ||||||
|  | 			type="checkbox" | ||||||
|  | 			:unchecked-value="false" | ||||||
|  | 			:value="true" | ||||||
|  | 			v-slot="{ value, field, errorMessage }" | ||||||
|  | 		> | ||||||
|  | 			<a-tooltip> | ||||||
|  | 				<template #title> | ||||||
|  | 					Hides your story from everyone except you and site admins. | ||||||
|  | 				</template> | ||||||
|  | 				<a-checkbox v-bind="field"> Hidden </a-checkbox> | ||||||
|  | 			</a-tooltip> | ||||||
|  | 		</Field> | ||||||
|  | 		<a-row> | ||||||
|  | 			<a-col :span="24"> | ||||||
|  | 				<genre /> | ||||||
|  | 			</a-col> | ||||||
|  | 		</a-row> | ||||||
|  | 		<a-divider> Contents </a-divider> | ||||||
|  | 		<upload-or-paste /> | ||||||
|  | 		<Field :name="name + '.id'" v-if="!!data.id" :model-value="data.id" /> | ||||||
|  | 	</div> | ||||||
|  | </template> | ||||||
							
								
								
									
										151
									
								
								components/story/create/storyform.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								components/story/create/storyform.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | 	import draggable from "vuedraggable"; | ||||||
|  | 	import { v4 } from "uuid"; | ||||||
|  | 	import lmove from "lodash-move"; | ||||||
|  | 	import { Field, Form as veeForm, FieldArray, FieldEntry } from "vee-validate"; | ||||||
|  | 	import { log } from "~/lib/server/logger"; | ||||||
|  | 	import { storySchema } from "~/lib/client/storyFormSchema"; | ||||||
|  | 	import { | ||||||
|  | 		FormChapter, | ||||||
|  | 		FormStory, | ||||||
|  | 		defaultChapter, | ||||||
|  | 	} from "~/lib/client/types/form/story"; | ||||||
|  | 
 | ||||||
|  | 	import singleChapter from "./singleChapter.vue"; | ||||||
|  | 	import icon from "~/components/icon.vue"; | ||||||
|  | 
 | ||||||
|  | 	const props = defineProps<{ | ||||||
|  | 		data: FormStory; | ||||||
|  | 		canDraft?: boolean; | ||||||
|  | 		endpoint: string; | ||||||
|  | 	}>(); | ||||||
|  | 	let drag = false; | ||||||
|  | 	let acData = ref(props.data); | ||||||
|  | 	const expandos = ref<string[]>([]); | ||||||
|  | 
 | ||||||
|  | 	function logSubmit(values, actions) { | ||||||
|  | 		// log.debug("VALUE"); | ||||||
|  | 		// log.debug(values); | ||||||
|  | 		// log.debug(actions); | ||||||
|  | 	} | ||||||
|  | 	function onSubmit(values, actions) { | ||||||
|  | 		logSubmit(values, actions); | ||||||
|  | 	} | ||||||
|  | 	function inval({ values, errors, results }) { | ||||||
|  | 		logSubmit(values, undefined); | ||||||
|  | 	} | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  | 	<vee-form | ||||||
|  | 		:keep-values="true" | ||||||
|  | 		v-slot="{ values, setFieldValue }" | ||||||
|  | 		:validation-schema="storySchema" | ||||||
|  | 		:initial-values="data" | ||||||
|  | 		@submit="onSubmit" | ||||||
|  | 		@invalid-submit="inval" | ||||||
|  | 	> | ||||||
|  | 		<!-- <a-form v-bind:model="acData"> --> | ||||||
|  | 		<Field name="title" v-slot="{ value, field, errorMessage }"> | ||||||
|  | 			<a-form-item | ||||||
|  | 				label="Title" | ||||||
|  | 				:help="errorMessage" | ||||||
|  | 				:validate-status="!!errorMessage ? 'error' : undefined" | ||||||
|  | 			> | ||||||
|  | 				<a-input v-bind="field" :value="value" /> | ||||||
|  | 			</a-form-item> | ||||||
|  | 		</Field> | ||||||
|  | 		<Field | ||||||
|  | 			:unchecked-value="false" | ||||||
|  | 			:value="true" | ||||||
|  | 			type="checkbox" | ||||||
|  | 			name="completed" | ||||||
|  | 			v-slot="{ value, field, errorMessage }" | ||||||
|  | 		> | ||||||
|  | 			<a-checkbox v-bind="field"> Complete </a-checkbox> | ||||||
|  | 		</Field> | ||||||
|  | 		<a-divider /> | ||||||
|  | 		<!-- <test1/> --> | ||||||
|  | 		<field-array name="chapters" v-slot="{ fields, push, remove, move }"> | ||||||
|  | 			<draggable | ||||||
|  | 				:component-data="{ type: 'transtion-group' }" | ||||||
|  | 				@start="drag = true" | ||||||
|  | 				@end="drag = false" | ||||||
|  | 				v-model="values.chapters" | ||||||
|  | 				tag="div" | ||||||
|  | 				item-key="uuidKey" | ||||||
|  | 				@change=" | ||||||
|  | 					(e) => { | ||||||
|  | 						if (e.moved) { | ||||||
|  | 							// log.debug(e.moved); | ||||||
|  | 							move(e.moved.oldIndex, e.moved.newIndex); | ||||||
|  | 							acData.chapters = lmove( | ||||||
|  | 								acData.chapters, | ||||||
|  | 								e.moved.oldIndex, | ||||||
|  | 								e.moved.newIndex, | ||||||
|  | 							); | ||||||
|  | 							// log.debug(toRaw(acData.chapters.map((a) => toRaw(a)))); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				" | ||||||
|  | 			> | ||||||
|  | 				<template #item="{ element, index }"> | ||||||
|  | 					<a-collapse v-model:active-key="expandos" collapsible="icon"> | ||||||
|  | 						<a-collapse-panel :key="`${element.uuidKey}`"> | ||||||
|  | 							<template #header> | ||||||
|  | 								{{ values.chapters[index]?.chapterTitle || "Untitled" }} | ||||||
|  | 								<a-button | ||||||
|  | 									@click=" | ||||||
|  | 										(e) => { | ||||||
|  | 											let localFields = toRaw(fields); | ||||||
|  | 											// log.debug(`${index} | ${element.index}`); | ||||||
|  | 											// log.debug('fields->', localFields); | ||||||
|  | 											acData.chapters.splice(index, 1); | ||||||
|  | 											remove(index); | ||||||
|  | 											// todo renumber | ||||||
|  | 											// renumber() | ||||||
|  | 										} | ||||||
|  | 									" | ||||||
|  | 								> | ||||||
|  | 									<icon istyle="regular" name="trash" /> | ||||||
|  | 								</a-button> | ||||||
|  | 							</template> | ||||||
|  | 							<single-chapter :data="element" :name="`chapters[${index}]`" /> | ||||||
|  | 						</a-collapse-panel> | ||||||
|  | 					</a-collapse> | ||||||
|  | 				</template> | ||||||
|  | 				<template #footer> | ||||||
|  | 					<a-button | ||||||
|  | 						@click=" | ||||||
|  | 							(e) => { | ||||||
|  | 								if (!Array.isArray(values.chapters)) { | ||||||
|  | 									setFieldValue('chapters', []); | ||||||
|  | 								} | ||||||
|  | 								const chaps = [...toRaw(values.chapters)]; | ||||||
|  | 								let lastIndex = chaps.length - 1; | ||||||
|  | 								if (lastIndex < 0) lastIndex = 0; | ||||||
|  | 								let lastChapter = chaps[lastIndex]; | ||||||
|  | 								// log.debug('chaptrs->', chaps); | ||||||
|  | 								// log.debug('lastIndex->', lastIndex, lastChapter); | ||||||
|  | 								let newChapter = Object.assign({}, defaultChapter, { | ||||||
|  | 									summary: lastChapter?.summary || '', | ||||||
|  | 									index: (lastChapter?.index || 0) + 1, | ||||||
|  | 									bands: lastChapter?.bands || [], | ||||||
|  | 									characters: lastChapter?.characters || [], | ||||||
|  | 									relationships: lastChapter?.relationships || [], | ||||||
|  | 									uuidKey: v4(), | ||||||
|  | 									genre: lastChapter?.genre || [], | ||||||
|  | 								}); | ||||||
|  | 								// log.debug('nc->', newChapter); | ||||||
|  | 								push(newChapter); | ||||||
|  | 								acData.chapters.push(newChapter); | ||||||
|  | 							} | ||||||
|  | 						" | ||||||
|  | 					> | ||||||
|  | 						Add chapter | ||||||
|  | 					</a-button> | ||||||
|  | 				</template> | ||||||
|  | 			</draggable> | ||||||
|  | 		</field-array> | ||||||
|  | 		<a-button type="primary" html-type="submit">go.</a-button> | ||||||
|  | 	</vee-form> | ||||||
|  | </template> | ||||||
							
								
								
									
										53
									
								
								components/story/create/uploadOrPaste.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								components/story/create/uploadOrPaste.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | <script lang="ts" setup> | ||||||
|  | 	import { | ||||||
|  | 		Form as VeeForm, | ||||||
|  | 		Field as veeField, | ||||||
|  | 		useForm, | ||||||
|  | 		useField, | ||||||
|  | 		ErrorMessage, | ||||||
|  | 	} from "vee-validate"; | ||||||
|  | 	import { story } from "~/lib/client/editorConfig"; | ||||||
|  | 	import icon from "~/components/icon.vue"; | ||||||
|  | 	import baseEditor from "../../baseEditor.vue"; | ||||||
|  | 	const fname = inject<string>("curName"); | ||||||
|  | 	const fileList = ref([]); | ||||||
|  | 	const potField = useField(fname + "pot"); | ||||||
|  | 	const fileField = useField(fname + "file"); | ||||||
|  | 	const { value: pvalue } = potField; | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  | 	<a-radio-group v-model:value="pvalue"> | ||||||
|  | 		<a-radio value="pasteOrType">Paste or type content</a-radio> | ||||||
|  | 		<a-radio value="upload">Upload a file</a-radio> | ||||||
|  | 	</a-radio-group> | ||||||
|  | 	<br /> | ||||||
|  | 	<br /> | ||||||
|  | 	<base-editor | ||||||
|  | 		label="" | ||||||
|  | 		v-if="pvalue === 'pasteOrType'" | ||||||
|  | 		:init="story" | ||||||
|  | 		:name="fname + 'content'" | ||||||
|  | 	/> | ||||||
|  | 	<a-upload | ||||||
|  | 		:with-credentials="true" | ||||||
|  | 		v-model:file-list="fileList" | ||||||
|  | 		v-else-if="pvalue === 'upload'" | ||||||
|  | 		:name="fname + 'file'" | ||||||
|  | 		accept=".doc,.docx,.md,.markdown" | ||||||
|  | 		:max-count="1" | ||||||
|  | 		@change=" | ||||||
|  | 			({ file }) => { | ||||||
|  | 				let resp = JSON.parse(file.response); | ||||||
|  | 				if (resp.success) { | ||||||
|  | 					fileField.setValue(resp.fileName); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		" | ||||||
|  | 	> | ||||||
|  | 		<a-button type="primary"> | ||||||
|  | 			<icon istyle="regular" name="upload" /><span style="margin-left: 0.5em"> | ||||||
|  | 				Upload a file</span | ||||||
|  | 			> | ||||||
|  | 		</a-button> | ||||||
|  | 	</a-upload> | ||||||
|  | </template> | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user