44
packages/client/src/components/page/page.block.vue
Normal file
44
packages/client/src/components/page/page.block.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<component :is="'x-' + block.type" :block="block" :hpml="hpml" :key="block.id" :h="h"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import XText from './page.text.vue';
|
||||
import XSection from './page.section.vue';
|
||||
import XImage from './page.image.vue';
|
||||
import XButton from './page.button.vue';
|
||||
import XNumberInput from './page.number-input.vue';
|
||||
import XTextInput from './page.text-input.vue';
|
||||
import XTextareaInput from './page.textarea-input.vue';
|
||||
import XSwitch from './page.switch.vue';
|
||||
import XIf from './page.if.vue';
|
||||
import XTextarea from './page.textarea.vue';
|
||||
import XPost from './page.post.vue';
|
||||
import XCounter from './page.counter.vue';
|
||||
import XRadioButton from './page.radio-button.vue';
|
||||
import XCanvas from './page.canvas.vue';
|
||||
import XNote from './page.note.vue';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { Block } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas, XNote
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<Block>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
},
|
||||
h: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
66
packages/client/src/components/page/page.button.vue
Normal file
66
packages/client/src/components/page/page.button.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div>
|
||||
<MkButton class="kudkigyw" @click="click()" :primary="block.primary">{{ hpml.interpolate(block.text) }}</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, unref } from 'vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { ButtonBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkButton
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<ButtonBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
if (this.block.action === 'dialog') {
|
||||
this.hpml.eval();
|
||||
os.dialog({
|
||||
text: this.hpml.interpolate(this.block.content)
|
||||
});
|
||||
} else if (this.block.action === 'resetRandom') {
|
||||
this.hpml.updateRandomSeed(Math.random());
|
||||
this.hpml.eval();
|
||||
} else if (this.block.action === 'pushEvent') {
|
||||
os.api('page-push', {
|
||||
pageId: this.hpml.page.id,
|
||||
event: this.block.event,
|
||||
...(this.block.var ? {
|
||||
var: unref(this.hpml.vars)[this.block.var]
|
||||
} : {})
|
||||
});
|
||||
|
||||
os.dialog({
|
||||
type: 'success',
|
||||
text: this.hpml.interpolate(this.block.message)
|
||||
});
|
||||
} else if (this.block.action === 'callAiScript') {
|
||||
this.hpml.callAiScript(this.block.fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kudkigyw {
|
||||
display: inline-block;
|
||||
min-width: 200px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
49
packages/client/src/components/page/page.canvas.vue
Normal file
49
packages/client/src/components/page/page.canvas.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="ysrxegms">
|
||||
<canvas ref="canvas" :width="block.width" :height="block.height"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, PropType, Ref, ref } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { CanvasBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<CanvasBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const canvas: Ref<any> = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
props.hpml.registerCanvas(props.block.name, canvas.value);
|
||||
});
|
||||
|
||||
return {
|
||||
canvas
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ysrxegms {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
overflow: auto;
|
||||
max-width: 100%;
|
||||
|
||||
> canvas {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
52
packages/client/src/components/page/page.counter.vue
Normal file
52
packages/client/src/components/page/page.counter.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div>
|
||||
<MkButton class="llumlmnx" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { CounterVarBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkButton
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<CounterVarBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function click() {
|
||||
props.hpml.updatePageVar(props.block.name, value.value + (props.block.inc || 1));
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
click
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.llumlmnx {
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
31
packages/client/src/components/page/page.if.vue
Normal file
31
packages/client/src/components/page/page.if.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div v-show="hpml.vars.value[block.var]">
|
||||
<XBlock v-for="child in block.children" :block="child" :hpml="hpml" :key="child.id" :h="h"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { IfBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { defineComponent, defineAsyncComponent, PropType } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XBlock: defineAsyncComponent(() => import('./page.block.vue'))
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<IfBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
},
|
||||
h: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
40
packages/client/src/components/page/page.image.vue
Normal file
40
packages/client/src/components/page/page.image.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="lzyxtsnt">
|
||||
<img v-if="image" :src="image.url"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { ImageBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<ImageBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const image = props.hpml.page.attachedFiles.find(x => x.id === props.block.fileId);
|
||||
|
||||
return {
|
||||
image
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lzyxtsnt {
|
||||
> img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
47
packages/client/src/components/page/page.note.vue
Normal file
47
packages/client/src/components/page/page.note.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div class="voxdxuby">
|
||||
<XNote v-if="note && !block.detailed" v-model:note="note" :key="note.id + ':normal'"/>
|
||||
<XNoteDetailed v-if="note && block.detailed" v-model:note="note" :key="note.id + ':detail'"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, PropType, Ref, ref } from 'vue';
|
||||
import XNote from '@/components/note.vue';
|
||||
import XNoteDetailed from '@/components/note-detailed.vue';
|
||||
import * as os from '@/os';
|
||||
import { NoteBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XNote,
|
||||
XNoteDetailed,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<NoteBlock>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const note: Ref<Record<string, any> | null> = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
os.api('notes/show', { noteId: props.block.note })
|
||||
.then(result => {
|
||||
note.value = result;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
note
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.voxdxuby {
|
||||
margin: 1em 0;
|
||||
}
|
||||
</style>
|
55
packages/client/src/components/page/page.number-input.vue
Normal file
55
packages/client/src/components/page/page.number-input.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
<MkInput class="kudkigyw" :model-value="value" @update:modelValue="updateValue($event)" type="number">
|
||||
<template #label>{{ hpml.interpolate(block.text) }}</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkInput from '../form/input.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { NumberInputVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkInput
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<NumberInputVarBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kudkigyw {
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
109
packages/client/src/components/page/page.post.vue
Normal file
109
packages/client/src/components/page/page.post.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="ngbfujlo">
|
||||
<MkTextarea :model-value="text" readonly style="margin: 0;"></MkTextarea>
|
||||
<MkButton class="button" primary @click="post()" :disabled="posting || posted">
|
||||
<i v-if="posted" class="fas fa-check"></i>
|
||||
<i v-else class="fas fa-paper-plane"></i>
|
||||
</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import MkTextarea from '../form/textarea.vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import { apiUrl } from '@/config';
|
||||
import * as os from '@/os';
|
||||
import { PostBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkTextarea,
|
||||
MkButton,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<PostBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: this.hpml.interpolate(this.block.text),
|
||||
posted: false,
|
||||
posting: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'hpml.vars': {
|
||||
handler() {
|
||||
this.text = this.hpml.interpolate(this.block.text);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
const promise = new Promise((ok) => {
|
||||
const canvas = this.hpml.canvases[this.block.canvasId];
|
||||
canvas.toBlob(blob => {
|
||||
const data = new FormData();
|
||||
data.append('file', blob);
|
||||
data.append('i', this.$i.token);
|
||||
if (this.$store.state.uploadFolder) {
|
||||
data.append('folderId', this.$store.state.uploadFolder);
|
||||
}
|
||||
|
||||
fetch(apiUrl + '/drive/files/create', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(f => {
|
||||
ok(f);
|
||||
})
|
||||
});
|
||||
});
|
||||
os.promiseDialog(promise);
|
||||
return promise;
|
||||
},
|
||||
async post() {
|
||||
this.posting = true;
|
||||
const file = this.block.attachCanvasImage ? await this.upload() : null;
|
||||
os.apiWithDialog('notes/create', {
|
||||
text: this.text === '' ? null : this.text,
|
||||
fileIds: file ? [file.id] : undefined,
|
||||
}).then(() => {
|
||||
this.posted = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ngbfujlo {
|
||||
position: relative;
|
||||
padding: 32px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px var(--shadow);
|
||||
z-index: 1;
|
||||
|
||||
> .button {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding: 16px;
|
||||
|
||||
> .button {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
45
packages/client/src/components/page/page.radio-button.vue
Normal file
45
packages/client/src/components/page/page.radio-button.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>{{ hpml.interpolate(block.title) }}</div>
|
||||
<MkRadio v-for="item in block.values" :modelValue="value" @update:modelValue="updateValue($event)" :value="item" :key="item">{{ item }}</MkRadio>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkRadio from '../form/radio.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { RadioButtonVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkRadio
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<RadioButtonVarBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue: string) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
60
packages/client/src/components/page/page.section.vue
Normal file
60
packages/client/src/components/page/page.section.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<section class="sdgxphyu">
|
||||
<component :is="'h' + h">{{ block.title }}</component>
|
||||
|
||||
<div class="children">
|
||||
<XBlock v-for="child in block.children" :block="child" :hpml="hpml" :key="child.id" :h="h + 1"/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent, PropType } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { SectionBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XBlock: defineAsyncComponent(() => import('./page.block.vue'))
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<SectionBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
},
|
||||
h: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sdgxphyu {
|
||||
margin: 1.5em 0;
|
||||
|
||||
> h2 {
|
||||
font-size: 1.35em;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
> h3 {
|
||||
font-size: 1em;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
> h4 {
|
||||
font-size: 1em;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
> .children {
|
||||
//padding 16px
|
||||
}
|
||||
}
|
||||
</style>
|
55
packages/client/src/components/page/page.switch.vue
Normal file
55
packages/client/src/components/page/page.switch.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="hkcxmtwj">
|
||||
<MkSwitch :model-value="value" @update:modelValue="updateValue($event)">{{ hpml.interpolate(block.text) }}</MkSwitch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkSwitch from '../form/switch.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { SwitchVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkSwitch
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<SwitchVarBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue: boolean) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hkcxmtwj {
|
||||
display: inline-block;
|
||||
margin: 16px auto;
|
||||
|
||||
& + .hkcxmtwj {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
55
packages/client/src/components/page/page.text-input.vue
Normal file
55
packages/client/src/components/page/page.text-input.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
<MkInput class="kudkigyw" :model-value="value" @update:modelValue="updateValue($event)" type="text">
|
||||
<template #label>{{ hpml.interpolate(block.text) }}</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkInput from '../form/input.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { TextInputVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkInput
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<TextInputVarBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kudkigyw {
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
68
packages/client/src/components/page/page.text.vue
Normal file
68
packages/client/src/components/page/page.text.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="mrdgzndn">
|
||||
<Mfm :text="text" :is-note="false" :i="$i" :key="text"/>
|
||||
<MkUrlPreview v-for="url in urls" :url="url" :key="url" class="url"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { TextBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { defineAsyncComponent, defineComponent, PropType } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkUrlPreview: defineAsyncComponent(() => import('@/components/url-preview.vue')),
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<TextBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: this.hpml.interpolate(this.block.text),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
urls(): string[] {
|
||||
if (this.text) {
|
||||
return extractUrlFromMfm(mfm.parse(this.text));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'hpml.vars': {
|
||||
handler() {
|
||||
this.text = this.hpml.interpolate(this.block.text);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mrdgzndn {
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
> .url {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
}
|
||||
</style>
|
47
packages/client/src/components/page/page.textarea-input.vue
Normal file
47
packages/client/src/components/page/page.textarea-input.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<MkTextarea :model-value="value" @update:modelValue="updateValue($event)">
|
||||
<template #label>{{ hpml.interpolate(block.text) }}</template>
|
||||
</MkTextarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkTextarea from '../form/textarea.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { HpmlTextInput } from '@/scripts/hpml';
|
||||
import { TextInputVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkTextarea
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<TextInputVarBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
39
packages/client/src/components/page/page.textarea.vue
Normal file
39
packages/client/src/components/page/page.textarea.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<MkTextarea :model-value="text" readonly></MkTextarea>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { TextBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import MkTextarea from '../form/textarea.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkTextarea
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<TextBlock>,
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: this.hpml.interpolate(this.block.text),
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'hpml.vars': {
|
||||
handler() {
|
||||
this.text = this.hpml.interpolate(this.block.text);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
86
packages/client/src/components/page/page.vue
Normal file
86
packages/client/src/components/page/page.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }" v-if="hpml">
|
||||
<XBlock v-for="child in page.content" :block="child" :hpml="hpml" :key="child.id" :h="2"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, nextTick, onUnmounted, PropType } from 'vue';
|
||||
import { parse } from '@syuilo/aiscript';
|
||||
import XBlock from './page.block.vue';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { url } from '@/config';
|
||||
import { $i } from '@/account';
|
||||
import { defaultStore } from '@/store';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XBlock
|
||||
},
|
||||
props: {
|
||||
page: {
|
||||
type: Object as PropType<Record<string, any>>,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
|
||||
const hpml = new Hpml(props.page, {
|
||||
randomSeed: Math.random(),
|
||||
visitor: $i,
|
||||
url: url,
|
||||
enableAiScript: !defaultStore.state.disablePagesScript
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (props.page.script && hpml.aiscript) {
|
||||
let ast;
|
||||
try {
|
||||
ast = parse(props.page.script);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
/*os.dialog({
|
||||
type: 'error',
|
||||
text: 'Syntax error :('
|
||||
});*/
|
||||
return;
|
||||
}
|
||||
hpml.aiscript.exec(ast).then(() => {
|
||||
hpml.eval();
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
/*os.dialog({
|
||||
type: 'error',
|
||||
text: e
|
||||
});*/
|
||||
});
|
||||
} else {
|
||||
hpml.eval();
|
||||
}
|
||||
});
|
||||
onUnmounted(() => {
|
||||
if (hpml.aiscript) hpml.aiscript.abort();
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
hpml,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iroscrza {
|
||||
&.serif {
|
||||
> div {
|
||||
font-family: serif;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user