Skip to content

Instantly share code, notes, and snippets.

@taxilian
Last active July 9, 2021 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taxilian/f4747451671285c4d836e7dab00605b3 to your computer and use it in GitHub Desktop.
Save taxilian/f4747451671285c4d836e7dab00605b3 to your computer and use it in GitHub Desktop.
Dialog abstraction example
import type Vue from 'vue';
type HSGenericDialogConstructor<PropNames extends string, RetType> =
new(...args: any[]) => HSGenericDialog<PropNames, RetType>;
export interface HSGenericDialog<PropNames extends string = string, RetType = any> {
submit(...args: any[]): RetType;
settableProperties: PropNames[] | readonly PropNames[];
}
type DialogReturnType<T extends HSGenericDialogConstructor<any, any>> =
T extends HSGenericDialogConstructor<any, infer R> ? R : never;
type DialogPropertiesList<T extends HSGenericDialogConstructor<any, any>> =
T extends HSGenericDialogConstructor<infer R, any> ? R : never;
type DialogPropertiesType<T extends HSGenericDialogConstructor<any, any>> = Pick<InstanceType<T>, DialogPropertiesList<T>>;
/**
* This relies on vuetify-dialog to work
*/
export async function showDialog<DialogType extends HSGenericDialogConstructor<any, any>>(v: Vue, dlg: DialogType, props: DialogPropertiesType<DialogType>) {
type RType = DialogReturnType<DialogType>;
const dialogDisplay = await v.$dialog.show(dlg, props);
const result: RType | null = await dialogDisplay.wait();
return result;
}
<script lang="ts">
import {showDialog} from './dialogMgr';
@Component()
export default class MyOtherComponent extends Vue {
markdown = '(some loaded markdown here)';
async openDialog() {
const dlgModule = await import(/* webpackChunkName: "common_markdownEditor" */ './MarkdownRichEditDialog.vue');
const dlg = dlgModule.default;
const result = await showDialog(this, dlg, {
title: "Edit markdown",
markdown: this.markdown,
});
if (result) {
this.markdown = result;
}
}
}
</script>
<template>
<v-card class="mx-auto">
<v-card-title v-text="title"></v-card-title>
<v-card-text cols="8" class="py-5 px-7">
<vue-editor id="mdEditor" v-model="markdown" :editorToolbar="simpleToolbar"></vue-editor>
</v-card-text>
<v-card-actions class="justify-space-around pb-6">
<v-btn
class="col-5 mx-1"
color="primary"
@click="accept"
>
<v-icon left>$vuetify.icons.fasCheckCircle</v-icon>
<i18next path="shared:accept" />
</v-btn>
<v-btn
class="col-5 mx-1"
color="secondary"
@click="cancel"
>
<v-icon left>$vuetify.icons.fasTimesCircle</v-icon>
<i18next path="shared:cancel" />
</v-btn>
</v-card-actions>
</v-card>
</template>
<script lang="ts">
import { HSGenericDialog } from './dialogMgr';
import Vue from 'vue';
import {Component, Prop, Emit} from 'vue-property-decorator';
import { VueEditor } from "vue2-editor";
@Component({
components: {
VueEditor,
},
})
export default class MarkdownRichEditDialog extends Vue implements HSGenericDialog {
@Prop({required: true})
title!: string;
@Prop({required: true})
markdown!: string;
readonly settableProperties = <const>['title', 'markdown'];
simpleToolbar = [
[{header: [false, 2, 3, 4]}],
["bold", "italic", "underline", "strike"],
['blockquote', {header: 1}, {header: 2}],
[{list: 'ordered'}, {list: 'bullet'}, {indent: '-1'}, {indent: '+1'}],
['link', 'image'],
['clean'],
];
cancel() {
this.submit();
}
accept() {
this.submit(this.markdown);
}
@Emit('submit')
submit(v?: string) { return v; }
}
</script>
<style lang="scss" scoped>
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment