Commits (10)
......@@ -12,6 +12,8 @@
:validation="$v.local[key]",
:attributes="field.attributes",
:label="$t(field.label)",
:fieldLabel="field.fieldLabel ? $t(field.fieldLabel) : undefined",
:handler="field.handler",
:helper-label="$t(field.helperLabel)",
:error-label="$t(field.errorLabel)",
:class="{ 'col-xl-6': !field.fullWidth, 'col-12': field.fullWidth }"
......@@ -25,6 +27,8 @@
:validation="field.validators ? $v.local[key] : undefined",
:attributes="field.attributes",
:label="$t(field.label)",
:fieldLabel="field.fieldLabel ? $t(field.fieldLabel) : undefined",
:handler="field.handler",
:helper-label="$t(field.helperLabel)",
:error-label="$t(field.errorLabel)",
:class="{ 'col-xl-6': !field.fullWidth, 'col-12': field.fullWidth }"
......
<template lang="pug">
q-input(v-if="type === 'hidden'", :type="type", v-model="local")
q-field(v-else, :dark="true", :label="fieldLabel", :error="validation ? validation.$error : undefined",
:error-label="errorLabel", :helper="helperLabel || ''")
:error-label="errorLabel", :helper="helperLabel || ''", orientation="vertical")
q-select(v-if="type === 'select'", :float-label="label", :dark="true", v-model="local", :options="selectOptions")
q-chips-input.q-my-md(v-else-if="type === 'chips'", :float-label="label", :dark="true", v-model="local",
chips-color="white", chips-bg-color="grey", @duplicate="duplicate()")
q-autocomplete.bg-grey-9(@search="autocompleteSearch", @selected="autocompleteSelected")
uploader(v-else-if="type === 'file'", dark, :url="url", @finish="onFileFinish", @select="onFileSelect", :headers="headers", :fields="uploadFields || []")
q-input(v-else, :dark="true", :float-label="label", :type="type", v-model="local", :attributes="attributes")
</template>
<script>
import { mapGetters } from 'vuex'
export default {
props: [
'value',
......@@ -21,7 +23,9 @@
'errorLabel',
'helperLabel',
'selectOptions',
'autocompleteOptions'
'autocompleteOptions',
'uploadFields',
'handler'
],
data () {
return {
......@@ -29,6 +33,17 @@
}
},
computed: {
...mapGetters({
user: 'auth/getUserState'
}),
url () {
return this.user ? `${process.env.API_HOST}/assets/user-${this.user.uuid}` : undefined
},
headers () {
return {
Authorization: `Bearer ${this.$auth.token}`
}
},
error () {
if (this.type === 'hidden') return
return this.validation && this.validation.$error
......@@ -66,6 +81,13 @@
},
autocompleteSelected (item) {
console.debug('FormRow: autocompleteSelected', item)
},
onFileSelect (selection) {
this.$emit('select', selection)
},
onFileFinish (responses) {
this.local = responses
if (typeof this.handler === 'function') this.handler(responses)
}
},
created () {
......
<template lang="pug">
div
// q-window-resize-observable(@resize="onWindowResize")
canvas(ref="three")
</template>
<script>
import path from 'path'
import { dom } from 'quasar'
const { height, width } = dom
const THREE = require('three')
global.THREE = THREE
require('three/examples/js/controls/OrbitControls')
require('three/examples/js/loaders/BVHLoader.js')
export default {
name: 'BVHPlayer',
props: {
bvhPath: String,
scale: Number,
loop: Boolean,
dump: Boolean,
compact: Boolean,
euler: Boolean,
backgroundColor: { type: String, default: '#000000' },
useOSC: { type: Boolean, default: true },
remoteAddress: String,
remotePort: Number
},
data () {
return {
skeletonName: undefined,
sender: undefined,
camera: undefined,
controls: undefined,
scene: undefined,
renderer: undefined,
stats: undefined,
clipAction: undefined,
mixers: [],
skeletons: [],
frames: [],
boneNames: []
}
},
async mounted () {
this.initThreeJS()
await this.loadBVH(this.bvhPath)
},
watch: {
async bvhPath (val) {
await this.loadBVH(val)
}
},
methods: {
onWindowResize (size) {
if (!this.camera || !this.renderer) return
this.camera.aspect = size.width / size.height
this.camera.updateProjectionMatrix()
this.renderer.setSize(size.width, size.height)
},
initThreeJS () {
// const w = window.innerWidth
// const h = window.innerHeight
const w = width(this.$el)
const h = height(this.$el)
this.clock = new THREE.Clock()
this.camera = new THREE.PerspectiveCamera(60, w / h, 1, 5000)
this.camera.position.set(0, 200, 400)
this.controls = new THREE.OrbitControls(this.camera, this.$refs.three)
this.controls.minDistance = 10
this.controls.maxDistance = 1000
this.scene = new THREE.Scene()
this.scene.background = new THREE.Color(this.backgroundColor)
this.scene.add(new THREE.GridHelper(400, 10))
// renderer
this.renderer = new THREE.WebGLRenderer({
canvas: this.$refs.three,
antialias: true
})
this.renderer.setPixelRatio(window.devicePixelRatio)
// this.renderer.setSize(this.$refs.three.offsetWidth, this.$refs.three.offsetHeight)
this.renderer.setSize(w, h)
this.animate()
},
async loadBVH (bvhPath) {
if (!this.bvhPath) return
const loader = new THREE.BVHLoader()
this.skeletonName = path.basename(bvhPath, path.extname(bvhPath))
loader.load(this.bvhPath, this.handleBVHLoaded)
},
handleBVHLoaded (result) {
const scaleVec = new THREE.Vector3(this.scale, this.scale, this.scale)
const skeletonHelper = new THREE.SkeletonHelper(result.skeleton.bones[0])
skeletonHelper.skeleton = result.skeleton // allow animation mixer to bind to SkeletonHelper directly
const boneContainer = new THREE.Group()
boneContainer.add(result.skeleton.bones[0])
boneContainer.scale.copy(scaleVec)
this.scene.add(skeletonHelper)
this.scene.add(boneContainer)
// play animation
const mixer = new THREE.AnimationMixer(skeletonHelper)
const clipAction = mixer.clipAction(result.clip)
.setLoop(this.loop ? THREE.LoopRepeat : THREE.LoopOnce)
.setEffectiveWeight(1.0)
clipAction.play()
mixer.update(0)
this.clipAction = clipAction
this.mixers.push(mixer)
this.skeletons.push(skeletonHelper)
},
async animate () {
requestAnimationFrame(this.animate)
const delta = this.clock.getDelta()
if (this.mixers.length > 0) {
this.mixers.forEach(mixer => {
mixer.update(delta)
})
}
this.renderer.render(this.scene, this.camera)
}
}
}
</script>
<style scoped lang="stylus">
canvas
margin: 0
padding: 0
width: 100vh
height: 100vh
</style>
......@@ -101,6 +101,11 @@
label: 'Groups',
route: 'users.groups',
path: '/users/groups'
},
assets: {
label: 'Assets',
route: 'users.assets',
path: '/users/assets'
}
}
}
......@@ -117,6 +122,10 @@
(t === 'users' && parts[1] === 'groups_edit')) return true
else return false
},
isAssets () {
const parts = this.$route.name.split('.')
return parts[0] === 'users' && parts[1].indexOf('assets') === 0
},
createScreen () {
const parts = this.$route.name.split('.')
return parts[parts.length - 1] === 'create' || parts[parts.length - 1] === 'groups_create'
......@@ -130,6 +139,7 @@
if (t === 'users' && parts[1] === 'groups') t = 'groups'
if (t === 'users' && parts[1] === 'groups_create') t = 'groups'
if (t === 'users' && parts[1] === 'groups_edit') t = 'groups'
if (t === 'users' && parts[1].indexOf('assets') === 0) t = 'assets'
if (t in this.topLevel) {
let _label = this.topLevel[t].label
......@@ -298,6 +308,13 @@
name: 'users.groups_create'
}
}
if (this.breadcrumbs[0].label === 'Assets' && this.$route.name !== 'users.assets_upload' && !this.breadcrumbs[1]) {
ab = {
label: this.$t('navigation.users.assets_upload'),
route: 'assets/upload',
name: 'users.assets_upload'
}
}
if (this.timeline) {
ab = {
label: this.$t('buttons.add_media'),
......
......@@ -235,6 +235,28 @@
q-item-side(v-if="currentRoute === 'users.groups_create'")
q-btn.bg-primary.text-white(type="a", to="/users/groups", icon="clear", round, size="sm")
// ------------------------------------------------------------------------------------------------------ assets
q-item.q-pa-none.ui-border-bottom(v-if="user && showAssets", multiline)
q-item-main
q-item-tile
user-nav-button.text-white(
:route="{ name: 'users.assets' }",
:label="$t('navigation.users.assets')",
name="users.assets",
icon="insert_drive_file")
q-item.q-my-sm.lt-sm(v-if="currentApp === 'assets'")
q-item-main
user-nav-button.text-white.round-borders(
:route="'/users/assets/upload'",
:label="$t('navigation.users.assets_upload')",
:name="'users.assets_upload'",
:icon="'add'",
:disabled="currentRoute === 'users.assets_upload'",
:class="[currentRoute === 'users.assets_upload' ? 'bg-grey-9' : 'bg-primary']")
q-item-side(v-if="currentRoute === 'users.assets_upload'")
q-btn.bg-primary.text-white(type="a", :to="{ name: 'users.assets' }", icon="clear", round, size="sm")
// -------------------------------------------------------------------------------------------- account settings
q-item.q-pa-none.ui-border-bottom(v-if="user", multiline, :class="{'active-app': currentApp === 'users'}")
q-item-main
......@@ -315,6 +337,10 @@
groups: [
'users.groups',
'users.groups_edit'
],
assets: [
'users.assets',
'users.assets_upload'
]
},
activeUserButtons: [],
......@@ -342,6 +368,9 @@
showGroups () {
return !process.env.UI_HIDE_GROUPS
},
showAssets () {
return process.env.UI_SHOW_ASSETS
},
editUserURL () {
return process.env.OAUTH_EDIT_PROFILE_URL
},
......@@ -376,6 +405,7 @@
let routeSplit = typeof route.name === 'string' ? route.name.split('.') : undefined
if (routeSplit && routeSplit[0] !== 'site') this.currentApp = routeSplit[0]
if (routeSplit && route.name.indexOf('users.assets') === 0) this.currentApp = 'assets'
else this.currentApp = 'Motionbank'
if (routeSplit && routeSplit[1].substr(0, 6) === 'groups') this.currentApp = 'groups'
......
......@@ -27,11 +27,14 @@
export default {
name: 'Permissions',
components: { ContentBlock, Headline, GroupsStepper },
props: ['resource'],
props: ['resource', 'simple'],
data () {
return {
type: undefined,
aclOptions: [
aclOptions: this.simple ? [
{ label: this.$t('labels.none'), value: undefined },
{ label: this.$t('labels.view'), value: 'view' }
] : [
{ label: this.$t('labels.none'), value: undefined },
{ label: this.$t('labels.view'), value: 'view' },
{ label: this.$t('labels.contribute'), value: 'contribute' },
......@@ -83,6 +86,7 @@
},
methods: {
getText () {
if (this.simple) return ''
let route = this.$route
let routeSplit = typeof route.name === 'string' ? route.name.split('.') : undefined
return this.$t('help.acl.' + routeSplit[0])
......
......@@ -26,9 +26,12 @@
multiple () {
this.allowMultiple = this.multiple
},
fields () {
fields: {
deep: true,
handler () {
this.addFields = this.fields || []
}
}
},
methods: {
onSelect (files) {
......