implemented a first version of the custom context menu
This commit is contained in:
parent
0ba8e96b6d
commit
e3a016e778
@ -6,7 +6,9 @@ This is just the WebUI for deemix, it should be used with deemix-pyweb or someth
|
|||||||
|
|
||||||
- Use Vue as much as possible
|
- Use Vue as much as possible
|
||||||
- First step: rewrite the app in Single File Components way ✅
|
- First step: rewrite the app in Single File Components way ✅
|
||||||
- Second step: Implement custom contextmenu
|
- Second step: Implement custom contextmenu ⚒
|
||||||
|
- Implemented a first version
|
||||||
|
- Need heavy testing and more features
|
||||||
- Third step: Implement routing for the whole app using Vue Router
|
- Third step: Implement routing for the whole app using Vue Router
|
||||||
- Fourth step: Remove jQuery
|
- Fourth step: Remove jQuery
|
||||||
- Make i18n async (https://kazupon.github.io/vue-i18n/guide/lazy-loading.html)
|
- Make i18n async (https://kazupon.github.io/vue-i18n/guide/lazy-loading.html)
|
||||||
|
File diff suppressed because one or more lines are too long
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
<TheTrackPreview />
|
<TheTrackPreview />
|
||||||
<TheQualityModal />
|
<TheQualityModal />
|
||||||
|
|
||||||
|
<TheContextMenu />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ import TheMainContent from '@components/TheMainContent.vue'
|
|||||||
import TheTrackPreview from '@components/TheTrackPreview.vue'
|
import TheTrackPreview from '@components/TheTrackPreview.vue'
|
||||||
import TheQualityModal from '@components/TheQualityModal.vue'
|
import TheQualityModal from '@components/TheQualityModal.vue'
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
||||||
|
import TheContextMenu from '@components/TheContextMenu.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -23,10 +26,8 @@ export default {
|
|||||||
TheMainContent,
|
TheMainContent,
|
||||||
TheTrackPreview,
|
TheTrackPreview,
|
||||||
TheQualityModal,
|
TheQualityModal,
|
||||||
BaseLoadingPlaceholder
|
BaseLoadingPlaceholder,
|
||||||
|
TheContextMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
157
src/components/TheContextMenu.vue
Normal file
157
src/components/TheContextMenu.vue
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<div class="context-menu" v-show="contextMenuOpen" ref="contextMenu">
|
||||||
|
<button class="menu-option" v-for="option of options" :key="option.label" @click.prevent="option.action">
|
||||||
|
<span class="menu-option__text">{{ option.label }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
contextMenuOpen: false
|
||||||
|
}),
|
||||||
|
// Using computed properties because this data is not meant to be reactive
|
||||||
|
// In this way it's cached
|
||||||
|
// https://vuejs.org/v2/guide/computed.html
|
||||||
|
computed: {
|
||||||
|
options() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Cut',
|
||||||
|
// Use arrow functions to keep the Vue instance in 'this'
|
||||||
|
// Use normal functions to keep the object instance in 'this'
|
||||||
|
action: () => {
|
||||||
|
document.execCommand('Cut')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Copy',
|
||||||
|
action: () => {
|
||||||
|
document.execCommand('Copy')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Paste',
|
||||||
|
action: () => {
|
||||||
|
navigator.clipboard.readText().then(text => {
|
||||||
|
document.execCommand('insertText', undefined, text)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
document.body.addEventListener('contextmenu', contextMenuEvent => {
|
||||||
|
contextMenuEvent.preventDefault()
|
||||||
|
let { pageX, pageY } = contextMenuEvent
|
||||||
|
|
||||||
|
this.$refs.contextMenu.style.top = `${pageY}px`
|
||||||
|
this.$refs.contextMenu.style.left = `${pageX}px`
|
||||||
|
this.contextMenuOpen = true
|
||||||
|
})
|
||||||
|
|
||||||
|
document.body.addEventListener('click', () => {
|
||||||
|
this.$nextTick().then(() => {
|
||||||
|
this.contextMenuOpen = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.context-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
min-width: 100px;
|
||||||
|
background: var(--foreground-inverted);
|
||||||
|
border-radius: 7px;
|
||||||
|
box-shadow: 4px 10px 18px 0px hsla(0, 0%, 0%, 0.15);
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding-left: 10px;
|
||||||
|
color: var(--foreground);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-radius: 7px 7px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-radius: 0 0 7px 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--table-highlight);
|
||||||
|
filter: brightness(150%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: var(--accent-text);
|
||||||
|
color: unset;
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
background-color: unset;
|
||||||
|
min-width: unset;
|
||||||
|
position: unset;
|
||||||
|
border: unset;
|
||||||
|
border-radius: unset;
|
||||||
|
font-family: unset;
|
||||||
|
font-weight: unset;
|
||||||
|
font-size: unset;
|
||||||
|
padding: unset;
|
||||||
|
margin-right: unset;
|
||||||
|
height: unset;
|
||||||
|
text-transform: unset;
|
||||||
|
cursor: unset;
|
||||||
|
transition: unset;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
background-color: unset;
|
||||||
|
color: unset;
|
||||||
|
opacity: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selective {
|
||||||
|
background-color: unset;
|
||||||
|
color: unset;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: unset;
|
||||||
|
color: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.with_icon {
|
||||||
|
display: unset;
|
||||||
|
align-items: unset;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-left: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: unset;
|
||||||
|
transform: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: unset;
|
||||||
|
border: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -15,9 +15,6 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
TheMiddleSection,
|
TheMiddleSection,
|
||||||
TheDownloadTab
|
TheDownloadTab
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
console.log(this.$route)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -293,7 +293,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
console.log('tracklist mounted')
|
|
||||||
EventBus.$on('tracklistTab:reset', this.reset)
|
EventBus.$on('tracklistTab:reset', this.reset)
|
||||||
EventBus.$on('tracklistTab:selectRow', this.selectRow)
|
EventBus.$on('tracklistTab:selectRow', this.selectRow)
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ import VueRouter from 'vue-router'
|
|||||||
|
|
||||||
import TracklistTab from '@components/TracklistTab.vue'
|
import TracklistTab from '@components/TracklistTab.vue'
|
||||||
|
|
||||||
console.log(TracklistTab)
|
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@ -29,7 +27,6 @@ const router = new VueRouter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
console.log({ from, to })
|
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user