refactoring

Resolve #7779
This commit is contained in:
syuilo
2021-11-12 02:02:25 +09:00
parent 037837b551
commit 0e4a111f81
1714 changed files with 20803 additions and 11751 deletions

View File

@@ -0,0 +1,84 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.button }}</template>
<section class="xfhsjczc">
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._button.text }}</template></MkInput>
<MkSwitch v-model="value.primary"><span>{{ $ts._pages.blocks._button.colored }}</span></MkSwitch>
<MkSelect v-model="value.action">
<template #label>{{ $ts._pages.blocks._button.action }}</template>
<option value="dialog">{{ $ts._pages.blocks._button._action.dialog }}</option>
<option value="resetRandom">{{ $ts._pages.blocks._button._action.resetRandom }}</option>
<option value="pushEvent">{{ $ts._pages.blocks._button._action.pushEvent }}</option>
<option value="callAiScript">{{ $ts._pages.blocks._button._action.callAiScript }}</option>
</MkSelect>
<template v-if="value.action === 'dialog'">
<MkInput v-model="value.content"><template #label>{{ $ts._pages.blocks._button._action._dialog.content }}</template></MkInput>
</template>
<template v-else-if="value.action === 'pushEvent'">
<MkInput v-model="value.event"><template #label>{{ $ts._pages.blocks._button._action._pushEvent.event }}</template></MkInput>
<MkInput v-model="value.message"><template #label>{{ $ts._pages.blocks._button._action._pushEvent.message }}</template></MkInput>
<MkSelect v-model="value.var">
<template #label>{{ $ts._pages.blocks._button._action._pushEvent.variable }}</template>
<option :value="null">{{ $t('_pages.blocks._button._action._pushEvent.no-variable') }}</option>
<option v-for="v in hpml.getVarsByType()" :value="v.name">{{ v.name }}</option>
<optgroup :label="$ts._pages.script.pageVariables">
<option v-for="v in hpml.getPageVarsByType()" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$ts._pages.script.enviromentVariables">
<option v-for="v in hpml.getEnvVarsByType()" :value="v">{{ v }}</option>
</optgroup>
</MkSelect>
</template>
<template v-else-if="value.action === 'callAiScript'">
<MkInput v-model="value.fn"><template #label>{{ $ts._pages.blocks._button._action._callAiScript.functionName }}</template></MkInput>
</template>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkSelect from '@/components/form/select.vue';
import MkInput from '@/components/form/input.vue';
import MkSwitch from '@/components/form/switch.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkSelect, MkInput, MkSwitch
},
props: {
value: {
required: true
},
hpml: {
required: true,
},
},
data() {
return {
};
},
created() {
if (this.value.text == null) this.value.text = '';
if (this.value.action == null) this.value.action = 'dialog';
if (this.value.content == null) this.value.content = null;
if (this.value.event == null) this.value.event = null;
if (this.value.message == null) this.value.message = null;
if (this.value.primary == null) this.value.primary = false;
if (this.value.var == null) this.value.var = null;
if (this.value.fn == null) this.value.fn = null;
},
});
</script>
<style lang="scss" scoped>
.xfhsjczc {
padding: 0 16px 0 16px;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-paint-brush"></i> {{ $ts._pages.blocks.canvas }}</template>
<section style="padding: 0 16px 0 16px;">
<MkInput v-model="value.name">
<template #prefix><i class="fas fa-magic"></i></template>
<template #label>{{ $ts._pages.blocks._canvas.id }}</template>
</MkInput>
<MkInput v-model="value.width" type="number">
<template #label>{{ $ts._pages.blocks._canvas.width }}</template>
<template #suffix>px</template>
</MkInput>
<MkInput v-model="value.height" type="number">
<template #label>{{ $ts._pages.blocks._canvas.height }}</template>
<template #suffix>px</template>
</MkInput>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.name == null) this.value.name = '';
if (this.value.width == null) this.value.width = 300;
if (this.value.height == null) this.value.height = 200;
},
});
</script>

View File

@@ -0,0 +1,46 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.counter }}</template>
<section style="padding: 0 16px 0 16px;">
<MkInput v-model="value.name">
<template #prefix><i class="fas fa-magic"></i></template>
<template #label>{{ $ts._pages.blocks._counter.name }}</template>
</MkInput>
<MkInput v-model="value.text">
<template #label>{{ $ts._pages.blocks._counter.text }}</template>
</MkInput>
<MkInput v-model="value.inc" type="number">
<template #label>{{ $ts._pages.blocks._counter.inc }}</template>
</MkInput>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.name == null) this.value.name = '';
},
});
</script>

View File

@@ -0,0 +1,84 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-question"></i> {{ $ts._pages.blocks.if }}</template>
<template #func>
<button @click="add()" class="_button">
<i class="fas fa-plus"></i>
</button>
</template>
<section class="romcojzs">
<MkSelect v-model="value.var">
<template #label>{{ $ts._pages.blocks._if.variable }}</template>
<option v-for="v in hpml.getVarsByType('boolean')" :value="v.name">{{ v.name }}</option>
<optgroup :label="$ts._pages.script.pageVariables">
<option v-for="v in hpml.getPageVarsByType('boolean')" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$ts._pages.script.enviromentVariables">
<option v-for="v in hpml.getEnvVarsByType('boolean')" :value="v">{{ v }}</option>
</optgroup>
</MkSelect>
<XBlocks class="children" v-model="value.children" :hpml="hpml"/>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue';
import { v4 as uuid } from 'uuid';
import XContainer from '../page-editor.container.vue';
import MkSelect from '@/components/form/select.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkSelect,
XBlocks: defineAsyncComponent(() => import('../page-editor.blocks.vue')),
},
inject: ['getPageBlockList'],
props: {
value: {
required: true
},
hpml: {
required: true,
},
},
data() {
return {
};
},
created() {
if (this.value.children == null) this.value.children = [];
if (this.value.var === undefined) this.value.var = null;
},
methods: {
async add() {
const { canceled, result: type } = await os.dialog({
type: null,
title: this.$ts._pages.chooseBlock,
select: {
groupedItems: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid();
this.value.children.push({ id, type });
},
}
});
</script>
<style lang="scss" scoped>
.romcojzs {
padding: 0 16px 16px 16px;
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-image"></i> {{ $ts._pages.blocks.image }}</template>
<template #func>
<button @click="choose()">
<i class="fas fa-folder-open"></i>
</button>
</template>
<section class="oyyftmcf">
<MkDriveFileThumbnail class="preview" v-if="file" :file="file" fit="contain" @click="choose()"/>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkDriveFileThumbnail
},
props: {
value: {
required: true
},
},
data() {
return {
file: null,
};
},
created() {
if (this.value.fileId === undefined) this.value.fileId = null;
},
mounted() {
if (this.value.fileId == null) {
this.choose();
} else {
os.api('drive/files/show', {
fileId: this.value.fileId
}).then(file => {
this.file = file;
});
}
},
methods: {
async choose() {
os.selectDriveFile(false).then(file => {
this.file = file;
this.value.fileId = file.id;
});
},
}
});
</script>
<style lang="scss" scoped>
.oyyftmcf {
> .preview {
height: 150px;
}
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-sticky-note"></i> {{ $ts._pages.blocks.note }}</template>
<section style="padding: 0 16px 0 16px;">
<MkInput v-model="id">
<template #label>{{ $ts._pages.blocks._note.id }}</template>
<template #caption>{{ $ts._pages.blocks._note.idDescription }}</template>
</MkInput>
<MkSwitch v-model="value.detailed"><span>{{ $ts._pages.blocks._note.detailed }}</span></MkSwitch>
<XNote v-if="note && !value.detailed" v-model:note="note" :key="note.id + ':normal'" style="margin-bottom: 16px;"/>
<XNoteDetailed v-if="note && value.detailed" v-model:note="note" :key="note.id + ':detail'" style="margin-bottom: 16px;"/>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkInput from '@/components/form/input.vue';
import MkSwitch from '@/components/form/switch.vue';
import XNote from '@/components/note.vue';
import XNoteDetailed from '@/components/note-detailed.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkInput, MkSwitch, XNote, XNoteDetailed,
},
props: {
value: {
required: true
},
},
data() {
return {
id: this.value.note,
note: null,
};
},
watch: {
id: {
async handler() {
if (this.id && (this.id.startsWith('http://') || this.id.startsWith('https://'))) {
this.value.note = this.id.endsWith('/') ? this.id.substr(0, this.id.length - 1).split('/').pop() : this.id.split('/').pop();
} else {
this.value.note = this.id;
}
this.note = await os.api('notes/show', { noteId: this.value.note });
},
immediate: true
},
},
created() {
if (this.value.note == null) this.value.note = null;
if (this.value.detailed == null) this.value.detailed = false;
},
});
</script>

View File

@@ -0,0 +1,46 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.numberInput }}</template>
<section style="padding: 0 16px 0 16px;">
<MkInput v-model="value.name">
<template #prefix><i class="fas fa-magic"></i></template>
<template #label>{{ $ts._pages.blocks._numberInput.name }}</template>
</MkInput>
<MkInput v-model="value.text">
<template #label>{{ $ts._pages.blocks._numberInput.text }}</template>
</MkInput>
<MkInput v-model="value.default" type="number">
<template #label>{{ $ts._pages.blocks._numberInput.default }}</template>
</MkInput>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.name == null) this.value.name = '';
},
});
</script>

View File

@@ -0,0 +1,43 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-paper-plane"></i> {{ $ts._pages.blocks.post }}</template>
<section style="padding: 16px;">
<MkTextarea v-model="value.text"><template #label>{{ $ts._pages.blocks._post.text }}</template></MkTextarea>
<MkSwitch v-model="value.attachCanvasImage"><span>{{ $ts._pages.blocks._post.attachCanvasImage }}</span></MkSwitch>
<MkInput v-if="value.attachCanvasImage" v-model="value.canvasId"><template #label>{{ $ts._pages.blocks._post.canvasId }}</template></MkInput>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkTextarea from '@/components/form/textarea.vue';
import MkInput from '@/components/form/input.vue';
import MkSwitch from '@/components/form/switch.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkTextarea, MkInput, MkSwitch
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.text == null) this.value.text = '';
if (this.value.attachCanvasImage == null) this.value.attachCanvasImage = false;
if (this.value.canvasId == null) this.value.canvasId = '';
},
});
</script>

View File

@@ -0,0 +1,50 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.radioButton }}</template>
<section style="padding: 0 16px 16px 16px;">
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._radioButton.name }}</template></MkInput>
<MkInput v-model="value.title"><template #label>{{ $ts._pages.blocks._radioButton.title }}</template></MkInput>
<MkTextarea v-model="values"><template #label>{{ $ts._pages.blocks._radioButton.values }}</template></MkTextarea>
<MkInput v-model="value.default"><template #label>{{ $ts._pages.blocks._radioButton.default }}</template></MkInput>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkTextarea from '@/components/form/textarea.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkTextarea, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
values: '',
};
},
watch: {
values: {
handler() {
this.value.values = this.values.split('\n');
},
deep: true
}
},
created() {
if (this.value.name == null) this.value.name = '';
if (this.value.title == null) this.value.title = '';
if (this.value.values == null) this.value.values = [];
this.values = this.value.values.join('\n');
},
});
</script>

View File

@@ -0,0 +1,96 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-sticky-note"></i> {{ value.title }}</template>
<template #func>
<button @click="rename()" class="_button">
<i class="fas fa-pencil-alt"></i>
</button>
<button @click="add()" class="_button">
<i class="fas fa-plus"></i>
</button>
</template>
<section class="ilrvjyvi">
<XBlocks class="children" v-model="value.children" :hpml="hpml"/>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue';
import { v4 as uuid } from 'uuid';
import XContainer from '../page-editor.container.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer,
XBlocks: defineAsyncComponent(() => import('../page-editor.blocks.vue')),
},
inject: ['getPageBlockList'],
props: {
value: {
required: true
},
hpml: {
required: true,
},
},
data() {
return {
};
},
created() {
if (this.value.title == null) this.value.title = null;
if (this.value.children == null) this.value.children = [];
},
mounted() {
if (this.value.title == null) {
this.rename();
}
},
methods: {
async rename() {
const { canceled, result: title } = await os.dialog({
title: 'Enter title',
input: {
type: 'text',
default: this.value.title
},
showCancelButton: true
});
if (canceled) return;
this.value.title = title;
},
async add() {
const { canceled, result: type } = await os.dialog({
type: null,
title: this.$ts._pages.chooseBlock,
select: {
groupedItems: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid();
this.value.children.push({ id, type });
},
}
});
</script>
<style lang="scss" scoped>
.ilrvjyvi {
> .children {
padding: 16px;
}
}
</style>

View File

@@ -0,0 +1,46 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.switch }}</template>
<section class="kjuadyyj">
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._switch.name }}</template></MkInput>
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._switch.text }}</template></MkInput>
<MkSwitch v-model="value.default"><span>{{ $ts._pages.blocks._switch.default }}</span></MkSwitch>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkSwitch from '@/components/form/switch.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkSwitch, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.name == null) this.value.name = '';
},
});
</script>
<style lang="scss" scoped>
.kjuadyyj {
padding: 0 16px 16px 16px;
}
</style>

View File

@@ -0,0 +1,39 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.textInput }}</template>
<section style="padding: 0 16px 0 16px;">
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._textInput.name }}</template></MkInput>
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._textInput.text }}</template></MkInput>
<MkInput v-model="value.default" type="text"><template #label>{{ $ts._pages.blocks._textInput.default }}</template></MkInput>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.name == null) this.value.name = '';
},
});
</script>

View File

@@ -0,0 +1,57 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-align-left"></i> {{ $ts._pages.blocks.text }}</template>
<section class="vckmsadr">
<textarea v-model="value.text"></textarea>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.text == null) this.value.text = '';
},
});
</script>
<style lang="scss" scoped>
.vckmsadr {
> textarea {
display: block;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
min-width: 100%;
min-height: 150px;
border: none;
box-shadow: none;
padding: 16px;
background: transparent;
color: var(--fg);
font-size: 14px;
box-sizing: border-box;
}
}
</style>

View File

@@ -0,0 +1,40 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.textareaInput }}</template>
<section style="padding: 0 16px 16px 16px;">
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._textareaInput.name }}</template></MkInput>
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._textareaInput.text }}</template></MkInput>
<MkTextarea v-model="value.default"><template #label>{{ $ts._pages.blocks._textareaInput.default }}</template></MkTextarea>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkTextarea from '@/components/form/textarea.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer, MkTextarea, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.name == null) this.value.name = '';
},
});
</script>

View File

@@ -0,0 +1,57 @@
<template>
<XContainer @remove="() => $emit('remove')" :draggable="true">
<template #header><i class="fas fa-align-left"></i> {{ $ts._pages.blocks.textarea }}</template>
<section class="ihymsbbe">
<textarea v-model="value.text"></textarea>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XContainer from '../page-editor.container.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
};
},
created() {
if (this.value.text == null) this.value.text = '';
},
});
</script>
<style lang="scss" scoped>
.ihymsbbe {
> textarea {
display: block;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
min-width: 100%;
min-height: 150px;
border: none;
box-shadow: none;
padding: 16px;
background: transparent;
color: var(--fg);
font-size: 14px;
box-sizing: border-box;
}
}
</style>

View File

@@ -0,0 +1,78 @@
<template>
<XDraggable tag="div" v-model="blocks" item-key="id" handle=".drag-handle" :group="{ name: 'blocks' }" animation="150" swap-threshold="0.5">
<template #item="{element}">
<component :is="'x-' + element.type" :value="element" @update:value="updateItem" @remove="() => removeItem(element)" :hpml="hpml"/>
</template>
</XDraggable>
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue';
import XSection from './els/page-editor.el.section.vue';
import XText from './els/page-editor.el.text.vue';
import XTextarea from './els/page-editor.el.textarea.vue';
import XImage from './els/page-editor.el.image.vue';
import XButton from './els/page-editor.el.button.vue';
import XTextInput from './els/page-editor.el.text-input.vue';
import XTextareaInput from './els/page-editor.el.textarea-input.vue';
import XNumberInput from './els/page-editor.el.number-input.vue';
import XSwitch from './els/page-editor.el.switch.vue';
import XIf from './els/page-editor.el.if.vue';
import XPost from './els/page-editor.el.post.vue';
import XCounter from './els/page-editor.el.counter.vue';
import XRadioButton from './els/page-editor.el.radio-button.vue';
import XCanvas from './els/page-editor.el.canvas.vue';
import XNote from './els/page-editor.el.note.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XDraggable: defineAsyncComponent(() => import('vuedraggable').then(x => x.default)),
XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas, XNote
},
props: {
modelValue: {
type: Array,
required: true
},
hpml: {
required: true,
},
},
emits: ['update:modelValue'],
computed: {
blocks: {
get() {
return this.modelValue;
},
set(value) {
this.$emit('update:modelValue', value);
}
}
},
methods: {
updateItem(v) {
const i = this.blocks.findIndex(x => x.id === v.id);
const newValue = [
...this.blocks.slice(0, i),
v,
...this.blocks.slice(i + 1)
];
this.$emit('update:modelValue', newValue);
},
removeItem(el) {
const i = this.blocks.findIndex(x => x.id === el.id);
const newValue = [
...this.blocks.slice(0, i),
...this.blocks.slice(i + 1)
];
this.$emit('update:modelValue', newValue);
},
}
});
</script>

View File

@@ -0,0 +1,159 @@
<template>
<div class="cpjygsrt" :class="{ error: error != null, warn: warn != null }">
<header>
<div class="title"><slot name="header"></slot></div>
<div class="buttons">
<slot name="func"></slot>
<button v-if="removable" @click="remove()" class="_button">
<i class="fas fa-trash-alt"></i>
</button>
<button v-if="draggable" class="drag-handle _button">
<i class="fas fa-bars"></i>
</button>
<button @click="toggleContent(!showBody)" class="_button">
<template v-if="showBody"><i class="fas fa-angle-up"></i></template>
<template v-else><i class="fas fa-angle-down"></i></template>
</button>
</div>
</header>
<p v-show="showBody" class="error" v-if="error != null">{{ $t('_pages.script.typeError', { slot: error.arg + 1, expect: $t(`script.types.${error.expect}`), actual: $t(`script.types.${error.actual}`) }) }}</p>
<p v-show="showBody" class="warn" v-if="warn != null">{{ $t('_pages.script.thereIsEmptySlot', { slot: warn.slot + 1 }) }}</p>
<div v-show="showBody" class="body">
<slot></slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
expanded: {
type: Boolean,
default: true
},
removable: {
type: Boolean,
default: true
},
draggable: {
type: Boolean,
default: false
},
error: {
required: false,
default: null
},
warn: {
required: false,
default: null
}
},
emits: ['toggle', 'remove'],
data() {
return {
showBody: this.expanded,
};
},
methods: {
toggleContent(show: boolean) {
this.showBody = show;
this.$emit('toggle', show);
},
remove() {
this.$emit('remove');
}
}
});
</script>
<style lang="scss" scoped>
.cpjygsrt {
position: relative;
overflow: hidden;
background: var(--panel);
border: solid 2px var(--X12);
border-radius: 6px;
&:hover {
border: solid 2px var(--X13);
}
&.warn {
border: solid 2px #dec44c;
}
&.error {
border: solid 2px #f00;
}
& + .cpjygsrt {
margin-top: 16px;
}
> header {
> .title {
z-index: 1;
margin: 0;
padding: 0 16px;
line-height: 42px;
font-size: 0.9em;
font-weight: bold;
box-shadow: 0 1px rgba(#000, 0.07);
> i {
margin-right: 6px;
}
&:empty {
display: none;
}
}
> .buttons {
position: absolute;
z-index: 2;
top: 0;
right: 0;
> button {
padding: 0;
width: 42px;
font-size: 0.9em;
line-height: 42px;
}
.drag-handle {
cursor: move;
}
}
}
> .warn {
color: #b19e49;
margin: 0;
padding: 16px 16px 0 16px;
font-size: 14px;
}
> .error {
color: #f00;
margin: 0;
padding: 16px 16px 0 16px;
font-size: 14px;
}
> .body {
::v-deep(.juejbjww), ::v-deep(.eiipwacr) {
&:not(.inline):first-child {
margin-top: 28px;
}
&:not(.inline):last-child {
margin-bottom: 20px;
}
}
}
}
</style>

View File

@@ -0,0 +1,281 @@
<template>
<XContainer :removable="removable" @remove="() => $emit('remove')" :error="error" :warn="warn" :draggable="draggable">
<template #header><i v-if="icon" :class="icon"></i> <template v-if="title">{{ title }} <span class="turmquns" v-if="typeText">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
<template #func>
<button @click="changeType()" class="_button">
<i class="fas fa-pencil-alt"></i>
</button>
</template>
<section v-if="modelValue.type === null" class="pbglfege" @click="changeType()">
{{ $ts._pages.script.emptySlot }}
</section>
<section v-else-if="modelValue.type === 'text'" class="tbwccoaw">
<input v-model="modelValue.value"/>
</section>
<section v-else-if="modelValue.type === 'multiLineText'" class="tbwccoaw">
<textarea v-model="modelValue.value"></textarea>
</section>
<section v-else-if="modelValue.type === 'textList'" class="tbwccoaw">
<textarea v-model="modelValue.value" :placeholder="$ts._pages.script.blocks._textList.info"></textarea>
</section>
<section v-else-if="modelValue.type === 'number'" class="tbwccoaw">
<input v-model="modelValue.value" type="number"/>
</section>
<section v-else-if="modelValue.type === 'ref'" class="hpdwcrvs">
<select v-model="modelValue.value">
<option v-for="v in hpml.getVarsByType(getExpectedType ? getExpectedType() : null).filter(x => x.name !== name)" :value="v.name">{{ v.name }}</option>
<optgroup :label="$ts._pages.script.argVariables">
<option v-for="v in fnSlots" :value="v.name">{{ v.name }}</option>
</optgroup>
<optgroup :label="$ts._pages.script.pageVariables">
<option v-for="v in hpml.getPageVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$ts._pages.script.enviromentVariables">
<option v-for="v in hpml.getEnvVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option>
</optgroup>
</select>
</section>
<section v-else-if="modelValue.type === 'aiScriptVar'" class="tbwccoaw">
<input v-model="modelValue.value"/>
</section>
<section v-else-if="modelValue.type === 'fn'" class="" style="padding:0 16px 16px 16px;">
<MkTextarea v-model="slots">
<template #label>{{ $ts._pages.script.blocks._fn.slots }}</template>
<template #caption>{{ $t('_pages.script.blocks._fn.slots-info') }}</template>
</MkTextarea>
<XV v-if="modelValue.value.expression" v-model="modelValue.value.expression" :title="$t(`_pages.script.blocks._fn.arg1`)" :get-expected-type="() => null" :hpml="hpml" :fn-slots="value.value.slots" :name="name"/>
</section>
<section v-else-if="modelValue.type.startsWith('fn:')" class="" style="padding:16px;">
<XV v-for="(x, i) in modelValue.args" v-model="value.args[i]" :title="hpml.getVarByName(modelValue.type.split(':')[1]).value.slots[i].name" :get-expected-type="() => null" :hpml="hpml" :name="name" :key="i"/>
</section>
<section v-else class="" style="padding:16px;">
<XV v-for="(x, i) in modelValue.args" v-model="modelValue.args[i]" :title="$t(`_pages.script.blocks._${modelValue.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :hpml="hpml" :name="name" :fn-slots="fnSlots" :key="i"/>
</section>
</XContainer>
</template>
<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
import { v4 as uuid } from 'uuid';
import XContainer from './page-editor.container.vue';
import MkTextarea from '@/components/form/textarea.vue';
import { blockDefs } from '@/scripts/hpml/index';
import * as os from '@/os';
import { isLiteralValue } from '@/scripts/hpml/expr';
import { funcDefs } from '@/scripts/hpml/lib';
export default defineComponent({
components: {
XContainer, MkTextarea,
XV: defineAsyncComponent(() => import('./page-editor.script-block.vue')),
},
inject: ['getScriptBlockList'],
props: {
getExpectedType: {
required: false,
default: null
},
modelValue: {
required: true
},
title: {
required: false
},
removable: {
required: false,
default: false
},
hpml: {
required: true,
},
name: {
required: true,
},
fnSlots: {
required: false,
},
draggable: {
required: false,
default: false
}
},
data() {
return {
error: null,
warn: null,
slots: '',
};
},
computed: {
icon(): any {
if (this.modelValue.type === null) return null;
if (this.modelValue.type.startsWith('fn:')) return 'fas fa-plug';
return blockDefs.find(x => x.type === this.modelValue.type).icon;
},
typeText(): any {
if (this.modelValue.type === null) return null;
if (this.modelValue.type.startsWith('fn:')) return this.modelValue.type.split(':')[1];
return this.$t(`_pages.script.blocks.${this.modelValue.type}`);
},
},
watch: {
slots: {
handler() {
this.modelValue.value.slots = this.slots.split('\n').map(x => ({
name: x,
type: null
}));
},
deep: true
}
},
created() {
if (this.modelValue.value == null) this.modelValue.value = null;
if (this.modelValue.value && this.modelValue.value.slots) this.slots = this.modelValue.value.slots.map(x => x.name).join('\n');
this.$watch(() => this.modelValue.type, (t) => {
this.warn = null;
if (this.modelValue.type === 'fn') {
const id = uuid();
this.modelValue.value = {
slots: [],
expression: { id, type: null }
};
return;
}
if (this.modelValue.type && this.modelValue.type.startsWith('fn:')) {
const fnName = this.modelValue.type.split(':')[1];
const fn = this.hpml.getVarByName(fnName);
const empties = [];
for (let i = 0; i < fn.value.slots.length; i++) {
const id = uuid();
empties.push({ id, type: null });
}
this.modelValue.args = empties;
return;
}
if (isLiteralValue(this.modelValue)) return;
const empties = [];
for (let i = 0; i < funcDefs[this.modelValue.type].in.length; i++) {
const id = uuid();
empties.push({ id, type: null });
}
this.modelValue.args = empties;
for (let i = 0; i < funcDefs[this.modelValue.type].in.length; i++) {
const inType = funcDefs[this.modelValue.type].in[i];
if (typeof inType !== 'number') {
if (inType === 'number') this.modelValue.args[i].type = 'number';
if (inType === 'string') this.modelValue.args[i].type = 'text';
}
}
});
this.$watch(() => this.modelValue.args, (args) => {
if (args == null) {
this.warn = null;
return;
}
const emptySlotIndex = args.findIndex(x => x.type === null);
if (emptySlotIndex !== -1 && emptySlotIndex < args.length) {
this.warn = {
slot: emptySlotIndex
};
} else {
this.warn = null;
}
}, {
deep: true
});
this.$watch(() => this.hpml.variables, () => {
if (this.type != null && this.modelValue) {
this.error = this.hpml.typeCheck(this.modelValue);
}
}, {
deep: true
});
},
methods: {
async changeType() {
const { canceled, result: type } = await os.dialog({
type: null,
title: this.$ts._pages.selectType,
select: {
groupedItems: this.getScriptBlockList(this.getExpectedType ? this.getExpectedType() : null)
},
showCancelButton: true
});
if (canceled) return;
this.modelValue.type = type;
},
_getExpectedType(slot: number) {
return this.hpml.getExpectedType(this.modelValue, slot);
}
}
});
</script>
<style lang="scss" scoped>
.turmquns {
opacity: 0.7;
}
.pbglfege {
opacity: 0.5;
padding: 16px;
text-align: center;
cursor: pointer;
color: var(--fg);
}
.tbwccoaw {
> input,
> textarea {
display: block;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
max-width: 100%;
min-width: 100%;
border: none;
box-shadow: none;
padding: 16px;
font-size: 16px;
background: transparent;
color: var(--fg);
box-sizing: border-box;
}
> textarea {
min-height: 100px;
}
}
.hpdwcrvs {
padding: 16px;
> select {
display: block;
padding: 4px;
font-size: 16px;
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,561 @@
<template>
<div>
<div class="jqqmcavi" style="margin: 16px;">
<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton>
<MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
<MkButton inline @click="duplicate" class="button" v-if="pageId"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton>
<MkButton inline @click="del" class="button" v-if="pageId && !readonly" danger><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
</div>
<div v-if="tab === 'settings'">
<div style="padding: 16px;" class="_formRoot">
<MkInput v-model="title" class="_formBlock">
<template #label>{{ $ts._pages.title }}</template>
</MkInput>
<MkInput v-model="summary" class="_formBlock">
<template #label>{{ $ts._pages.summary }}</template>
</MkInput>
<MkInput v-model="name" class="_formBlock">
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
<template #label>{{ $ts._pages.url }}</template>
</MkInput>
<MkSwitch v-model="alignCenter" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch>
<MkSelect v-model="font" class="_formBlock">
<template #label>{{ $ts._pages.font }}</template>
<option value="serif">{{ $ts._pages.fontSerif }}</option>
<option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option>
</MkSelect>
<MkSwitch v-model="hideTitleWhenPinned" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch>
<div class="eyeCatch">
<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
<div v-else-if="eyeCatchingImage">
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
<MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
</div>
</div>
</div>
</div>
<div v-else-if="tab === 'contents'">
<div style="padding: 16px;">
<XBlocks class="content" v-model="content" :hpml="hpml"/>
<MkButton @click="add()" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
</div>
</div>
<div v-else-if="tab === 'variables'">
<div class="qmuvgica">
<XDraggable tag="div" class="variables" v-show="variables.length > 0" v-model="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
<template #item="{element}">
<XVariable
:modelValue="element"
:removable="true"
@remove="() => removeVariable(element)"
:hpml="hpml"
:name="element.name"
:title="element.name"
:draggable="true"
/>
</template>
</XDraggable>
<MkButton @click="addVariable()" class="add" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
</div>
</div>
<div v-else-if="tab === 'script'">
<div>
<MkTextarea class="_code" v-model="script"/>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent, computed } from 'vue';
import 'prismjs';
import { highlight, languages } from 'prismjs/components/prism-core';
import 'prismjs/components/prism-clike';
import 'prismjs/components/prism-javascript';
import 'prismjs/themes/prism-okaidia.css';
import 'vue-prism-editor/dist/prismeditor.min.css';
import { v4 as uuid } from 'uuid';
import XVariable from './page-editor.script-block.vue';
import XBlocks from './page-editor.blocks.vue';
import MkTextarea from '@/components/form/textarea.vue';
import MkContainer from '@/components/ui/container.vue';
import MkButton from '@/components/ui/button.vue';
import MkSelect from '@/components/form/select.vue';
import MkSwitch from '@/components/form/switch.vue';
import MkInput from '@/components/form/input.vue';
import { blockDefs } from '@/scripts/hpml/index';
import { HpmlTypeChecker } from '@/scripts/hpml/type-checker';
import { url } from '@/config';
import { collectPageVars } from '@/scripts/collect-page-vars';
import * as os from '@/os';
import { selectFile } from '@/scripts/select-file';
import * as symbols from '@/symbols';
export default defineComponent({
components: {
XDraggable: defineAsyncComponent(() => import('vuedraggable').then(x => x.default)),
XVariable, XBlocks, MkTextarea, MkContainer, MkButton, MkSelect, MkSwitch, MkInput,
},
props: {
initPageId: {
type: String,
required: false
},
initPageName: {
type: String,
required: false
},
initUser: {
type: String,
required: false
},
},
data() {
return {
[symbols.PAGE_INFO]: computed(() => {
let title = this.$ts._pages.newPage;
if (this.initPageId) {
title = this.$ts._pages.editPage;
}
else if (this.initPageName && this.initUser) {
title = this.$ts._pages.readPage;
}
return {
title: title,
icon: 'fas fa-pencil-alt',
bg: 'var(--bg)',
tabs: [{
active: this.tab === 'settings',
title: this.$ts._pages.pageSetting,
icon: 'fas fa-cog',
onClick: () => { this.tab = 'settings'; },
}, {
active: this.tab === 'contents',
title: this.$ts._pages.contents,
icon: 'fas fa-sticky-note',
onClick: () => { this.tab = 'contents'; },
}, {
active: this.tab === 'variables',
title: this.$ts._pages.variables,
icon: 'fas fa-magic',
onClick: () => { this.tab = 'variables'; },
}, {
active: this.tab === 'script',
title: this.$ts.script,
icon: 'fas fa-code',
onClick: () => { this.tab = 'script'; },
}],
};
}),
tab: 'settings',
author: this.$i,
readonly: false,
page: null,
pageId: null,
currentName: null,
title: '',
summary: null,
name: Date.now().toString(),
eyeCatchingImage: null,
eyeCatchingImageId: null,
font: 'sans-serif',
content: [],
alignCenter: false,
hideTitleWhenPinned: false,
variables: [],
hpml: null,
script: '',
url,
};
},
watch: {
async eyeCatchingImageId() {
if (this.eyeCatchingImageId == null) {
this.eyeCatchingImage = null;
} else {
this.eyeCatchingImage = await os.api('drive/files/show', {
fileId: this.eyeCatchingImageId,
});
}
},
},
async created() {
this.hpml = new HpmlTypeChecker();
this.$watch('variables', () => {
this.hpml.variables = this.variables;
}, { deep: true });
this.$watch('content', () => {
this.hpml.pageVars = collectPageVars(this.content);
}, { deep: true });
if (this.initPageId) {
this.page = await os.api('pages/show', {
pageId: this.initPageId,
});
} else if (this.initPageName && this.initUser) {
this.page = await os.api('pages/show', {
name: this.initPageName,
username: this.initUser,
});
this.readonly = true;
}
if (this.page) {
this.author = this.page.user;
this.pageId = this.page.id;
this.title = this.page.title;
this.name = this.page.name;
this.currentName = this.page.name;
this.summary = this.page.summary;
this.font = this.page.font;
this.script = this.page.script;
this.hideTitleWhenPinned = this.page.hideTitleWhenPinned;
this.alignCenter = this.page.alignCenter;
this.content = this.page.content;
this.variables = this.page.variables;
this.eyeCatchingImageId = this.page.eyeCatchingImageId;
} else {
const id = uuid();
this.content = [{
id,
type: 'text',
text: 'Hello World!'
}];
}
},
provide() {
return {
readonly: this.readonly,
getScriptBlockList: this.getScriptBlockList,
getPageBlockList: this.getPageBlockList
}
},
methods: {
getSaveOptions() {
return {
title: this.title.trim(),
name: this.name.trim(),
summary: this.summary,
font: this.font,
script: this.script,
hideTitleWhenPinned: this.hideTitleWhenPinned,
alignCenter: this.alignCenter,
content: this.content,
variables: this.variables,
eyeCatchingImageId: this.eyeCatchingImageId,
};
},
save() {
const options = this.getSaveOptions();
const onError = err => {
if (err.id == '3d81ceae-475f-4600-b2a8-2bc116157532') {
if (err.info.param == 'name') {
os.dialog({
type: 'error',
title: this.$ts._pages.invalidNameTitle,
text: this.$ts._pages.invalidNameText
});
}
} else if (err.code == 'NAME_ALREADY_EXISTS') {
os.dialog({
type: 'error',
text: this.$ts._pages.nameAlreadyExists
});
}
};
if (this.pageId) {
options.pageId = this.pageId;
os.api('pages/update', options)
.then(page => {
this.currentName = this.name.trim();
os.dialog({
type: 'success',
text: this.$ts._pages.updated
});
}).catch(onError);
} else {
os.api('pages/create', options)
.then(page => {
this.pageId = page.id;
this.currentName = this.name.trim();
os.dialog({
type: 'success',
text: this.$ts._pages.created
});
this.$router.push(`/pages/edit/${this.pageId}`);
}).catch(onError);
}
},
del() {
os.dialog({
type: 'warning',
text: this.$t('removeAreYouSure', { x: this.title.trim() }),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
os.api('pages/delete', {
pageId: this.pageId,
}).then(() => {
os.dialog({
type: 'success',
text: this.$ts._pages.deleted
});
this.$router.push(`/pages`);
});
});
},
duplicate() {
this.title = this.title + ' - copy';
this.name = this.name + '-copy';
os.api('pages/create', this.getSaveOptions()).then(page => {
this.pageId = page.id;
this.currentName = this.name.trim();
os.dialog({
type: 'success',
text: this.$ts._pages.created
});
this.$router.push(`/pages/edit/${this.pageId}`);
});
},
async add() {
const { canceled, result: type } = await os.dialog({
type: null,
title: this.$ts._pages.chooseBlock,
select: {
groupedItems: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid();
this.content.push({ id, type });
},
async addVariable() {
let { canceled, result: name } = await os.dialog({
title: this.$ts._pages.enterVariableName,
input: {
type: 'text',
},
showCancelButton: true
});
if (canceled) return;
name = name.trim();
if (this.hpml.isUsedName(name)) {
os.dialog({
type: 'error',
text: this.$ts._pages.variableNameIsAlreadyUsed
});
return;
}
const id = uuid();
this.variables.push({ id, name, type: null });
},
removeVariable(v) {
this.variables = this.variables.filter(x => x.name !== v.name);
},
getPageBlockList() {
return [{
label: this.$ts._pages.contentBlocks,
items: [
{ value: 'section', text: this.$ts._pages.blocks.section },
{ value: 'text', text: this.$ts._pages.blocks.text },
{ value: 'image', text: this.$ts._pages.blocks.image },
{ value: 'textarea', text: this.$ts._pages.blocks.textarea },
{ value: 'note', text: this.$ts._pages.blocks.note },
{ value: 'canvas', text: this.$ts._pages.blocks.canvas },
]
}, {
label: this.$ts._pages.inputBlocks,
items: [
{ value: 'button', text: this.$ts._pages.blocks.button },
{ value: 'radioButton', text: this.$ts._pages.blocks.radioButton },
{ value: 'textInput', text: this.$ts._pages.blocks.textInput },
{ value: 'textareaInput', text: this.$ts._pages.blocks.textareaInput },
{ value: 'numberInput', text: this.$ts._pages.blocks.numberInput },
{ value: 'switch', text: this.$ts._pages.blocks.switch },
{ value: 'counter', text: this.$ts._pages.blocks.counter }
]
}, {
label: this.$ts._pages.specialBlocks,
items: [
{ value: 'if', text: this.$ts._pages.blocks.if },
{ value: 'post', text: this.$ts._pages.blocks.post }
]
}];
},
getScriptBlockList(type: string = null) {
const list = [];
const blocks = blockDefs.filter(block => type === null || block.out === null || block.out === type || typeof block.out === 'number');
for (const block of blocks) {
const category = list.find(x => x.category === block.category);
if (category) {
category.items.push({
value: block.type,
text: this.$t(`_pages.script.blocks.${block.type}`)
});
} else {
list.push({
category: block.category,
label: this.$t(`_pages.script.categories.${block.category}`),
items: [{
value: block.type,
text: this.$t(`_pages.script.blocks.${block.type}`)
}]
});
}
}
const userFns = this.variables.filter(x => x.type === 'fn');
if (userFns.length > 0) {
list.unshift({
label: this.$t(`_pages.script.categories.fn`),
items: userFns.map(v => ({
value: 'fn:' + v.name,
text: v.name
}))
});
}
return list;
},
setEyeCatchingImage(e) {
selectFile(e.currentTarget || e.target, null, false).then(file => {
this.eyeCatchingImageId = file.id;
});
},
removeEyeCatchingImage() {
this.eyeCatchingImageId = null;
},
highlighter(code) {
return highlight(code, languages.js, 'javascript');
},
}
});
</script>
<style lang="scss" scoped>
.jqqmcavi {
> .button {
& + .button {
margin-left: 8px;
}
}
}
.gwbmwxkm {
position: relative;
> header {
> .title {
z-index: 1;
margin: 0;
padding: 0 16px;
line-height: 42px;
font-size: 0.9em;
font-weight: bold;
box-shadow: 0 1px rgba(#000, 0.07);
> i {
margin-right: 6px;
}
&:empty {
display: none;
}
}
> .buttons {
position: absolute;
z-index: 2;
top: 0;
right: 0;
> button {
padding: 0;
width: 42px;
font-size: 0.9em;
line-height: 42px;
}
}
}
> section {
padding: 0 32px 32px 32px;
@media (max-width: 500px) {
padding: 0 16px 16px 16px;
}
> .view {
display: inline-block;
margin: 16px 0 0 0;
font-size: 14px;
}
> .content {
margin-bottom: 16px;
}
> .eyeCatch {
margin-bottom: 16px;
> div {
> img {
max-width: 100%;
}
}
}
}
}
.qmuvgica {
padding: 16px;
> .variables {
margin-bottom: 16px;
}
> .add {
margin-bottom: 16px;
}
}
</style>