Add AiScript console widget
This commit is contained in:
		
							parent
							
								
									3d73ce63ca
								
							
						
					
					
						commit
						b2fb92cf0f
					
				
					 4 changed files with 176 additions and 3 deletions
				
			
		|  | @ -1067,6 +1067,7 @@ _widgets: | |||
|   onlineUsers: "オンラインユーザー" | ||||
|   jobQueue: "ジョブキュー" | ||||
|   serverMetric: "サーバーメトリクス" | ||||
|   aiscript: "AiScriptコンソール" | ||||
| 
 | ||||
| _cw: | ||||
|   hide: "隠す" | ||||
|  |  | |||
							
								
								
									
										164
									
								
								src/client/widgets/aiscript.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/client/widgets/aiscript.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,164 @@ | |||
| <template> | ||||
| <MkContainer :show-header="props.showHeader"> | ||||
| 	<template #header><Fa :icon="faTerminal"/>{{ $ts._widgets.aiscript }}</template> | ||||
| 
 | ||||
| 	<div class="uylguesu _monospace"> | ||||
| 		<textarea v-model="props.script" placeholder="(1 + 1)"></textarea> | ||||
| 		<button @click="run" class="_buttonPrimary">RUN</button> | ||||
| 		<div class="logs"> | ||||
| 			<div v-for="log in logs" class="log" :key="log.id" :class="{ print: log.print }">{{ log.text }}</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </MkContainer> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineComponent } from 'vue'; | ||||
| import { faTerminal } from '@fortawesome/free-solid-svg-icons'; | ||||
| import MkContainer from '@/components/ui/container.vue'; | ||||
| import define from './define'; | ||||
| import * as os from '@/os'; | ||||
| import { AiScript, parse, utils } from '@syuilo/aiscript'; | ||||
| import { createAiScriptEnv } from '@/scripts/aiscript/api'; | ||||
| 
 | ||||
| const widget = define({ | ||||
| 	name: 'aiscript', | ||||
| 	props: () => ({ | ||||
| 		showHeader: { | ||||
| 			type: 'boolean', | ||||
| 			default: true, | ||||
| 		}, | ||||
| 		script: { | ||||
| 			type: 'string', | ||||
| 			multiline: true, | ||||
| 			default: '(1 + 1)', | ||||
| 			hidden: true, | ||||
| 		}, | ||||
| 	}) | ||||
| }); | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	extends: widget, | ||||
| 	components: { | ||||
| 		MkContainer | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
| 		return { | ||||
| 			logs: [], | ||||
| 			faTerminal | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
| 	methods: { | ||||
| 		async run() { | ||||
| 			this.logs = []; | ||||
| 			const aiscript = new AiScript(createAiScriptEnv({ | ||||
| 				storageKey: 'widget' | ||||
| 			}), { | ||||
| 				in: (q) => { | ||||
| 					return new Promise(ok => { | ||||
| 						os.dialog({ | ||||
| 							title: q, | ||||
| 							input: {} | ||||
| 						}).then(({ canceled, result: a }) => { | ||||
| 							ok(a); | ||||
| 						}); | ||||
| 					}); | ||||
| 				}, | ||||
| 				out: (value) => { | ||||
| 					this.logs.push({ | ||||
| 						id: Math.random(), | ||||
| 						text: value.type === 'str' ? value.value : utils.valToString(value), | ||||
| 						print: true | ||||
| 					}); | ||||
| 				}, | ||||
| 				log: (type, params) => { | ||||
| 					switch (type) { | ||||
| 						case 'end': this.logs.push({ | ||||
| 							id: Math.random(), | ||||
| 							text: utils.valToString(params.val, true), | ||||
| 							print: false | ||||
| 						}); break; | ||||
| 						default: break; | ||||
| 					} | ||||
| 				} | ||||
| 			}); | ||||
| 
 | ||||
| 			let ast; | ||||
| 			try { | ||||
| 				ast = parse(this.props.script); | ||||
| 			} catch (e) { | ||||
| 				os.dialog({ | ||||
| 					type: 'error', | ||||
| 					text: 'Syntax error :(' | ||||
| 				}); | ||||
| 				return; | ||||
| 			} | ||||
| 			try { | ||||
| 				await aiscript.exec(ast); | ||||
| 			} catch (e) { | ||||
| 				os.dialog({ | ||||
| 					type: 'error', | ||||
| 					text: e | ||||
| 				}); | ||||
| 			} | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .uylguesu { | ||||
| 	text-align: right; | ||||
| 
 | ||||
| 	> textarea { | ||||
| 		display: block; | ||||
| 		width: 100%; | ||||
| 		max-width: 100%; | ||||
| 		min-width: 100%; | ||||
| 		padding: 16px; | ||||
| 		color: var(--fg); | ||||
| 		background: transparent; | ||||
| 		border: none; | ||||
| 		border-bottom: solid 1px var(--divider); | ||||
| 		border-radius: 0; | ||||
| 		box-sizing: border-box; | ||||
| 		font: inherit; | ||||
| 
 | ||||
| 		&:focus { | ||||
| 			outline: none; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> button { | ||||
| 		display: inline-block; | ||||
| 		margin: 8px; | ||||
| 		padding: 0 10px; | ||||
| 		height: 28px; | ||||
| 		outline: none; | ||||
| 		border-radius: 4px; | ||||
| 
 | ||||
| 		&:disabled { | ||||
| 			opacity: 0.7; | ||||
| 			cursor: default; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> .logs { | ||||
| 		border-top: solid 1px var(--divider); | ||||
| 		text-align: left; | ||||
| 		padding: 16px; | ||||
| 
 | ||||
| 		&:empty { | ||||
| 			display: none; | ||||
| 		} | ||||
| 
 | ||||
| 		> .log { | ||||
| 			&:not(.print) { | ||||
| 				opacity: 0.7; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -18,6 +18,7 @@ export default function(app: App) { | |||
| 	app.component('MkwOnlineUsers', defineAsyncComponent(() => import('./online-users.vue'))); | ||||
| 	app.component('MkwJobQueue', defineAsyncComponent(() => import('./job-queue.vue'))); | ||||
| 	app.component('MkwButton', defineAsyncComponent(() => import('./button.vue'))); | ||||
| 	app.component('MkwAiscript', defineAsyncComponent(() => import('./aiscript.vue'))); | ||||
| } | ||||
| 
 | ||||
| export const widgets = [ | ||||
|  | @ -38,4 +39,5 @@ export const widgets = [ | |||
| 	'onlineUsers', | ||||
| 	'jobQueue', | ||||
| 	'button', | ||||
| 	'aiscript', | ||||
| ]; | ||||
|  |  | |||
|  | @ -74,12 +74,18 @@ export default defineComponent({ | |||
| 		max-width: 100%; | ||||
| 		min-width: 100%; | ||||
| 		padding: 16px; | ||||
| 		color: var(--inputText); | ||||
| 		background: var(--face); | ||||
| 		color: var(--fg); | ||||
| 		background: transparent; | ||||
| 		border: none; | ||||
| 		border-bottom: solid var(--lineWidth) var(--faceDivider); | ||||
| 		border-bottom: solid 1px var(--divider); | ||||
| 		border-radius: 0; | ||||
| 		box-sizing: border-box; | ||||
| 		font: inherit; | ||||
| 		font-size: 0.9em; | ||||
| 
 | ||||
| 		&:focus { | ||||
| 			outline: none; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> button { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue