initial commit
commit
790c407c2e
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false,
|
||||
"targets": {
|
||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||
}
|
||||
}],
|
||||
"stage-2"
|
||||
],
|
||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
|
@ -0,0 +1,4 @@
|
|||
/build/
|
||||
/config/
|
||||
/dist/
|
||||
/*.js
|
|
@ -0,0 +1,29 @@
|
|||
// https://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
extends: [
|
||||
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
||||
'plugin:vue/essential',
|
||||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||
'standard'
|
||||
],
|
||||
// required to lint *.vue files
|
||||
plugins: [
|
||||
'vue'
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
// allow async-await
|
||||
'generator-star-spacing': 'off',
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
.DS_Store
|
||||
node_modules/
|
||||
/dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
|
@ -0,0 +1,10 @@
|
|||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
"postcss-import": {},
|
||||
"postcss-url": {},
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
# snowmix-vue
|
||||
|
||||
> Vue-based Snowmix frontend
|
||||
|
||||
## Build Setup
|
||||
|
||||
``` bash
|
||||
# install dependencies
|
||||
npm install
|
||||
|
||||
# serve with hot reload at localhost:8080
|
||||
npm run dev
|
||||
|
||||
# build for production with minification
|
||||
npm run build
|
||||
|
||||
# build for production and view the bundle analyzer report
|
||||
npm run build --report
|
||||
```
|
||||
|
||||
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
|
||||
|
||||
## Links?
|
||||
|
||||
* https://vuecomponent.github.io/ant-design/
|
||||
* http://kirillmurashov.com/vue-drag-resize/
|
|
@ -0,0 +1,7 @@
|
|||
'use strict'
|
||||
const merge = require('webpack-merge')
|
||||
const prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"'
|
||||
})
|
|
@ -0,0 +1,76 @@
|
|||
'use strict'
|
||||
// Template version: 1.3.1
|
||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
dev: {
|
||||
|
||||
// Paths
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
proxyTable: {},
|
||||
|
||||
// Various Dev Server settings
|
||||
host: 'localhost', // can be overwritten by process.env.HOST
|
||||
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||
autoOpenBrowser: false,
|
||||
errorOverlay: true,
|
||||
notifyOnErrors: true,
|
||||
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||
|
||||
// Use Eslint Loader?
|
||||
// If true, your code will be linted during bundling and
|
||||
// linting errors and warnings will be shown in the console.
|
||||
useEslint: true,
|
||||
// If true, eslint errors and warnings will also be shown in the error overlay
|
||||
// in the browser.
|
||||
showEslintErrorsInOverlay: false,
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
// https://webpack.js.org/configuration/devtool/#development
|
||||
devtool: 'cheap-module-eval-source-map',
|
||||
|
||||
// If you have problems debugging vue-files in devtools,
|
||||
// set this to false - it *may* help
|
||||
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||
cacheBusting: true,
|
||||
|
||||
cssSourceMap: true
|
||||
},
|
||||
|
||||
build: {
|
||||
// Template for index.html
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
|
||||
// Paths
|
||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
productionSourceMap: true,
|
||||
// https://webpack.js.org/configuration/devtool/#production
|
||||
devtool: '#source-map',
|
||||
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
'use strict'
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>antd-demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"name": "snowmix-vue",
|
||||
"version": "1.0.0",
|
||||
"description": "Quick and dirty Snowmix frontend in Vue.js",
|
||||
"author": "Piotr Dobrowolski <admin@tastycode.pl>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||
"start": "npm run dev",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"build": "node build/build.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^2.5.2",
|
||||
"vue-antd-ui": "^0.6.0",
|
||||
"vue-router": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.2",
|
||||
"babel-core": "^6.22.1",
|
||||
"babel-eslint": "^8.2.1",
|
||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"babel-plugin-transform-runtime": "^6.22.0",
|
||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
||||
"babel-preset-env": "^1.3.2",
|
||||
"babel-preset-stage-2": "^6.22.0",
|
||||
"chalk": "^2.0.1",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"css-loader": "^0.28.0",
|
||||
"eslint": "^4.15.0",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-friendly-formatter": "^3.0.0",
|
||||
"eslint-loader": "^1.7.1",
|
||||
"eslint-plugin-import": "^2.7.0",
|
||||
"eslint-plugin-node": "^5.2.0",
|
||||
"eslint-plugin-promise": "^3.4.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"eslint-plugin-vue": "^4.0.0",
|
||||
"extract-text-webpack-plugin": "^3.0.0",
|
||||
"file-loader": "^1.1.4",
|
||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"node-notifier": "^5.1.2",
|
||||
"optimize-css-assets-webpack-plugin": "^3.2.0",
|
||||
"ora": "^1.2.0",
|
||||
"portfinder": "^1.0.13",
|
||||
"postcss-import": "^11.0.0",
|
||||
"postcss-loader": "^2.0.8",
|
||||
"postcss-url": "^7.2.1",
|
||||
"rimraf": "^2.6.0",
|
||||
"semver": "^5.3.0",
|
||||
"shelljs": "^0.7.6",
|
||||
"uglifyjs-webpack-plugin": "^1.1.1",
|
||||
"url-loader": "^0.5.8",
|
||||
"vue-loader": "^13.3.0",
|
||||
"vue-style-loader": "^3.0.1",
|
||||
"vue-template-compiler": "^2.5.2",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-bundle-analyzer": "^2.9.0",
|
||||
"webpack-dev-server": "^2.9.1",
|
||||
"webpack-merge": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<!--router-view/>-->
|
||||
<a-row :gutter=4>
|
||||
<a-col :span="6">
|
||||
<Scene v-bind:frames="frames" />
|
||||
</a-col>
|
||||
<a-col :span="6" v-for="item in frames" :key="item.id">
|
||||
<Frame v-bind:frame="item" v-bind:sources="sources"/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!--
|
||||
<a-row>
|
||||
<a-col :span="6">
|
||||
<a-card>
|
||||
<DragParent v-model="positionScale" targetWidth="1280" targetHeight="720">
|
||||
<DraggableFrame v-for="frame in frames" :key="frame.id" v-model="frame.position" v-bind:scale="positionScale" v-if="positionScale > 0">
|
||||
</DraggableFrame>
|
||||
</DragParent>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Scene from './components/Scene.vue'
|
||||
import Frame from './components/Frame.vue'
|
||||
import DraggableFrame from './components/DraggableFrame.vue'
|
||||
import DragParent from './components/DragParent.vue'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Scene,
|
||||
Frame,
|
||||
DraggableFrame,
|
||||
DragParent
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
frames: [
|
||||
{
|
||||
id: 5,
|
||||
visible: true,
|
||||
front: {
|
||||
alpha: 0.9,
|
||||
source: 'feed:1'
|
||||
},
|
||||
back: {
|
||||
alpha: 0.9,
|
||||
source: 'feed:2'
|
||||
},
|
||||
position: { x: 0, y: 0, width: 1280, height: 720 }
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
visible: false,
|
||||
front: {
|
||||
alpha: 0.9,
|
||||
source: 'feed:2'
|
||||
},
|
||||
back: {
|
||||
alpha: 0.9,
|
||||
source: 'feed:1'
|
||||
},
|
||||
position: { x: 0, y: 0, width: 1280 / 2, height: 720 / 2 }
|
||||
}
|
||||
],
|
||||
sources: [
|
||||
{ id: 'feed:1', name: 'Camera', state: 'playing' },
|
||||
{ id: 'feed:2', name: 'HDMI Capture', state: 'pending' },
|
||||
{ id: 'image:1', name: 'Background' },
|
||||
{ id: 'image:2', name: 'Dead stream' }
|
||||
],
|
||||
positionScale: null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<div v-bind:style="{ position: 'relative', height: computedHeight }">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DragParent',
|
||||
props: ['scale', 'value', 'targetWidth', 'targetHeight'],
|
||||
computed: {
|
||||
computedHeight: function () {
|
||||
return (this.targetHeight * this.value) + 'px'
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.$nextTick(function () {
|
||||
console.info(this)
|
||||
var scale = this.$el.clientWidth / this.targetWidth
|
||||
console.info('New scale:', scale)
|
||||
this.$emit('input', scale)
|
||||
this.scale = scale
|
||||
this.$forceUpdate()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<vue-drag-resize
|
||||
:isActive="false" :x="value.x*scale" :y="value.y*scale" :w="value.width*scale" :h="value.height*scale"
|
||||
:parentLimitation="true" :aspectRatio="true" style="background: #eeeeeedd; outline: 1px solid #aaa;"
|
||||
:minw="1" :minh="1" v-on:resizing="resize" v-on:dragging="resize">
|
||||
<slot></slot>
|
||||
</vue-drag-resize>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DraggableFrame',
|
||||
props: ['scale', 'value'],
|
||||
methods: {
|
||||
resize (newRect) {
|
||||
var newPos = {
|
||||
x: Math.ceil(newRect.left / this.scale),
|
||||
y: Math.ceil(newRect.top / this.scale),
|
||||
width: Math.ceil(newRect.width / this.scale),
|
||||
height: Math.ceil(newRect.height / this.scale)
|
||||
}
|
||||
|
||||
this.$emit('input', newPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,74 @@
|
|||
<template>
|
||||
<a-card title="Frame 1">
|
||||
<!--<a href="#" slot="extra">more</a>-->
|
||||
<a-switch slot="extra" v-model="frame.visible" />
|
||||
<a-row type="flex" justify="center" align="top" style="height: 200px">
|
||||
<div style="float:left;height: 100%;">
|
||||
<a-slider vertical :min="0" :max="1.0" :step="0.01" v-model="frame.front.alpha"/>
|
||||
</div>
|
||||
<div style="float:left;height: 100%;flex-grow:1">
|
||||
<a-radio-group defaultValue="a" size="small">
|
||||
<a-radio-button value="a">Hangzhou</a-radio-button>
|
||||
<a-radio-button value="d">Chengdu</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div style="float:left;height: 100%;">
|
||||
<a-slider vertical :min="0" :max="1.0" :step="0.01" v-model="frame.back.alpha" />
|
||||
</div>
|
||||
</a-row>
|
||||
<a-tabs defaultActiveKey="1" size="small" :tabBarGutter="1" slot="actions">
|
||||
<a-tab-pane tab="Source" key="1">
|
||||
<a-row :gutter=4>
|
||||
<a-col :span=12>
|
||||
<a-select defaultValue="lucy" style="width:100%" v-model="frame.front.source">
|
||||
<a-select-opt-group>
|
||||
<span slot="label"><a-icon type="video-camera"/> Feed</span>
|
||||
<a-select-option value="feed:1"><a-badge status="success" text="Camera" /></a-select-option>
|
||||
<a-select-option value="feed:2"><a-badge status="warning" text="HDMI" /></a-select-option>
|
||||
</a-select-opt-group>
|
||||
<a-select-opt-group>
|
||||
<span slot="label"><a-icon type="picture"/> Image</span>
|
||||
<a-select-option value="image:1">yiminghe</a-select-option>
|
||||
</a-select-opt-group>
|
||||
<a-select-opt-group>
|
||||
<span slot="label">Others</span>
|
||||
</a-select-opt-group>
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :span=12>
|
||||
<a-select defaultValue="lucy" style="width:100%">
|
||||
<a-select-opt-group>
|
||||
<span slot="label"><a-icon type="user"/> Feed</span>
|
||||
<a-select-option value="jack">Jack</a-select-option>
|
||||
<a-select-option value="lucy">Lucy</a-select-option>
|
||||
</a-select-opt-group>
|
||||
<a-select-opt-group label="Image">
|
||||
<a-select-option value="Yiminghe">yiminghe</a-select-option>
|
||||
</a-select-opt-group>
|
||||
</a-select>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Frame',
|
||||
props: ['frame', 'sources'],
|
||||
data () {
|
||||
return {
|
||||
msg: 'Welcome to Your Vue.js App'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ant-card-body {
|
||||
padding: 10px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<a-card title="Scene 1">
|
||||
<a-row type="flex" justify="center" align="top" style="height: 200px">
|
||||
<div style="float:left;height: 100%;">
|
||||
<a-slider vertical :defaultValue="30" />
|
||||
</div>
|
||||
<div style="float:left;height: 100%;flex-grow:1">
|
||||
<a-button-group>
|
||||
<a-dropdown>
|
||||
<a-menu slot="overlay" @click="handleMenuClick">
|
||||
<a-menu-item key="1">1st menu item</a-menu-item>
|
||||
<a-menu-item key="2">2nd menu item</a-menu-item>
|
||||
<a-menu-item key="3">3rd item</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button style="margin-left: 8px">
|
||||
<a-icon type="down" /> Fade
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
<a-dropdown>
|
||||
<a-menu slot="overlay" @click="handleMenuClick">
|
||||
<a-menu-item key="1">1st menu item</a-menu-item>
|
||||
<a-menu-item key="2">2nd menu item</a-menu-item>
|
||||
<a-menu-item key="3">3rd item</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button style="margin-left: 8px">
|
||||
Cut <a-icon type="down" />
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</a-button-group>
|
||||
</div>
|
||||
<div style="float:left;height: 100%;">
|
||||
<a-slider vertical :defaultValue="30" />
|
||||
</div>
|
||||
</a-row>
|
||||
<a-tabs defaultActiveKey="1" size="small" tabBarGutter="1" slot="actions">
|
||||
<a-tab-pane tab="Placing" key="1">
|
||||
<div style="margin: 0 6px 6px 6px; border: 1px solid #999">
|
||||
<DragParent v-model="positionScale" targetWidth="1280" targetHeight="720">
|
||||
<DraggableFrame v-for="frame in frames" :key="frame.id" v-model="frame.position" v-bind:scale="positionScale" v-if="positionScale > 0">
|
||||
</DraggableFrame>
|
||||
</DragParent>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="Timing" key="2">
|
||||
<a-slider :defaultValue="30" />
|
||||
<a-slider :defaultValue="30" />
|
||||
<a-slider :defaultValue="30" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="Background" key="3">Tab 3</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DraggableFrame from './DraggableFrame.vue'
|
||||
import DragParent from './DragParent.vue'
|
||||
|
||||
export default {
|
||||
name: 'Scene',
|
||||
components: {
|
||||
DragParent,
|
||||
DraggableFrame
|
||||
},
|
||||
props: ['frames'],
|
||||
data () {
|
||||
return {
|
||||
positionScale: null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ant-card-body {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
.ant-card-head {
|
||||
padding: 0 10px;
|
||||
min-height: 40px;
|
||||
}
|
||||
.ant-card-head-title {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.ant-card-extra {
|
||||
padding: 6.5px 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,22 @@
|
|||
// The Vue build version to load with the `import` command
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
import Vue from 'vue'
|
||||
|
||||
import Antd from 'vue-antd-ui'
|
||||
import 'vue-antd-ui/dist/antd.css'
|
||||
import VueDragResize from 'vue-drag-resize'
|
||||
import router from './router'
|
||||
|
||||
import App from './App'
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Vue.component('vue-drag-resize', VueDragResize)
|
||||
Vue.use(Antd)
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
components: { App },
|
||||
template: '<App/>'
|
||||
})
|
|
@ -0,0 +1,15 @@
|
|||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import HelloWorld from '@/components/HelloWorld'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'HelloWorld',
|
||||
component: HelloWorld
|
||||
}
|
||||
]
|
||||
})
|
Loading…
Reference in New Issue