5096e74a60
* Added trash can function * Tweaked status text to always be the same * Removed some open second note code * Edior always focuses on text now * Added some extra loading note messages * Notes are now removed from search index when deleted * Lots more things happen and update in real time on multiple machines * Shared notes can be reverted * WAY more tests * Note Categories are much more reliable * Lots of code is much cleaner
390 lines
10 KiB
Vue
390 lines
10 KiB
Vue
<style scoped>
|
|
.slotholder {
|
|
height: 100vh;
|
|
width: 155px;
|
|
display: block;
|
|
float: left;
|
|
}
|
|
.global-menu {
|
|
width: 155px;
|
|
background: #221f2b;
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
display: block;
|
|
position: fixed;
|
|
z-index: 111;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
}
|
|
.menu-logo-display {
|
|
width: 25px;
|
|
margin: 5px 0 0 34px;
|
|
display: inline-block;
|
|
}
|
|
|
|
.menu-item {
|
|
color: #fff;
|
|
padding: 0.8em 10px 0.8em 10px;
|
|
display: inline-block;
|
|
width: 100%;
|
|
font-size: 1.15em;
|
|
box-sizing: border-box;
|
|
}
|
|
.menu-item i.icon {
|
|
margin-right: 10px;
|
|
}
|
|
.sub {
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.menu-section {}
|
|
.menu-section + .menu-section {
|
|
border-top: 1px solid #534c68;
|
|
}
|
|
.menu-button {
|
|
cursor: pointer;
|
|
}
|
|
.menu-button:hover {
|
|
background-color: #534c68;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.router-link-active i {
|
|
/*color: #16ab39;*/
|
|
}
|
|
.router-link-active {
|
|
background-color: #534c68;
|
|
}
|
|
|
|
.shade {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0,0,0,0.7);
|
|
z-index: 100;
|
|
cursor: pointer;
|
|
}
|
|
.top-menu-bar {
|
|
/*color: var(--text_color);*/
|
|
/*width: 100%;*/
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 999;
|
|
background-color: var(--background_color);
|
|
border-bottom: 1px solid;
|
|
border-color: var(--border_color);
|
|
padding: 5px 1rem 5px;
|
|
}
|
|
.place-holder {
|
|
width: 100%;
|
|
height: 50px;
|
|
}
|
|
.top-menu-bar img {
|
|
width: 30px;
|
|
height: 30px;
|
|
}
|
|
.version-display {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: -20px;
|
|
right: 0;
|
|
height: 30px;
|
|
padding: 5px 0;
|
|
text-align: center;
|
|
color: #8c80ae;
|
|
cursor: pointer;
|
|
}
|
|
|
|
</style>
|
|
|
|
<template>
|
|
<div>
|
|
|
|
<div class="place-holder" v-if="collapsed && !menuOpen"></div>
|
|
|
|
<!-- collapsed menu, appears as a bar -->
|
|
<div class="top-menu-bar" v-if="(collapsed || mobile) && !menuOpen">
|
|
<div class="ui grid">
|
|
|
|
<div class="seven wide column">
|
|
<div class="ui large basic compact icon button" v-on:click="collapseMenu">
|
|
<i class="green bars icon"></i>
|
|
</div>
|
|
|
|
<router-link v-if="loggedIn" class="ui large basic compact icon button" to="/notes" v-on:click.native="emitReloadEvent()">
|
|
<i class="green home icon"></i>
|
|
</router-link>
|
|
|
|
<router-link v-if="loggedIn" class="ui basic icon button" exact-active-class="active" to="/attachments">
|
|
<i class="open folder outline icon"></i>
|
|
</router-link>
|
|
|
|
</div>
|
|
|
|
<div class="two wide center aligned bottom aligned column">
|
|
<img loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
|
</div>
|
|
|
|
<div class="seven wide right aligned column">
|
|
|
|
<div v-on:click="toggleNightMode" class="ui large basic compact icon button">
|
|
<i class="green moon outline icon"></i>
|
|
</div>
|
|
|
|
<!-- mobile create note button -->
|
|
<span v-if="loggedIn">
|
|
<span v-if="!disableNewNote" @click="createNote" class="ui large green compact icon button">
|
|
<i class="plus icon"></i>
|
|
</span>
|
|
<span v-if="disableNewNote" class="ui large basic compact icon button">
|
|
<i class="grey plus icon"></i>
|
|
</span>
|
|
</span>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="shade" v-if="mobile && !collapsed" v-on:click="collapseMenu"></div>
|
|
|
|
<div class="slotholder" v-if="!collapsed && !mobile">
|
|
</div>
|
|
|
|
<div class="global-menu" v-if="!collapsed" v-on:click="menuClicked">
|
|
|
|
<div class="menu-section" v-on:click="collapseMenu">
|
|
<!-- <div class="menu-item menu-button" > -->
|
|
<i class="white angle left icon"></i>
|
|
<img class="menu-logo-display" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
|
<!-- </div> -->
|
|
</div>
|
|
|
|
<div class="menu-section" v-if="loggedIn">
|
|
<div v-if="!disableNewNote" @click="createNote" class="menu-item menu-item menu-button">
|
|
<div class="ui green button">
|
|
<i class="plus icon"></i>New Note
|
|
</div>
|
|
</div>
|
|
<div v-if="disableNewNote" class="menu-item menu-item menu-button">
|
|
<div class="ui basic button">
|
|
<i class="plus loading icon"></i>New Note
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="menu-section" v-if="loggedIn && $store.getters.totals && $store.getters.totals['totalNotes']">
|
|
<router-link exact-active-class="active" class="menu-item menu-button" to="/notes" v-on:click.native="emitReloadEvent()">
|
|
<i class="file outline icon"></i>Notes
|
|
<counter class="float-right" number-id="totalNotes" />
|
|
</router-link>
|
|
<div>
|
|
<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
|
|
<!-- <div v-on:click="updateFastFilters(0)" class="menu-item menu-button sub"><i class="grey linkify icon"></i>Links</div> -->
|
|
<!-- <div v-on:click="updateFastFilters(1)" class="menu-item menu-button sub"><i class="grey tags icon"></i>Tags</div> -->
|
|
</div>
|
|
</div>
|
|
|
|
<div class="menu-section" v-if="loggedIn && $store.getters.totals && $store.getters.totals['totalFiles']">
|
|
<router-link class="menu-item menu-button" exact-active-class="active" to="/attachments">
|
|
<i class="open folder outline icon"></i>Files
|
|
<counter class="float-right" number-id="totalFiles" />
|
|
</router-link>
|
|
</div>
|
|
|
|
<div class="menu-section" v-if="loggedIn">
|
|
<router-link v-if="loggedIn" exact-active-class="active" class="menu-item menu-button" to="/quick">
|
|
<i class="sticky note outline icon"></i>Scratch Pad
|
|
</router-link>
|
|
</div>
|
|
|
|
<div class="menu-section" v-if="!loggedIn">
|
|
<router-link v-if="!loggedIn" class="menu-item menu-button" exact-active-class="active" to="/">
|
|
<i class="home icon"></i>Welcome
|
|
</router-link>
|
|
|
|
<router-link exact-active-class="active" class="menu-item menu-button" to="/login">
|
|
<i class="plug icon"></i>Login
|
|
</router-link>
|
|
</div>
|
|
|
|
<div class="menu-section">
|
|
<div v-on:click="toggleNightMode" class="menu-item menu-button">
|
|
<span v-if="$store.getters.getIsNightMode == 0">
|
|
<i class="moon outline icon"></i>Black Theme</span>
|
|
<span v-if="$store.getters.getIsNightMode == 1">
|
|
<i class="moon outline icon"></i>Night Theme</span>
|
|
<span v-if="$store.getters.getIsNightMode == 2">
|
|
<i class="moon outline icon"></i>Light Theme</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="menu-section">
|
|
<router-link class="menu-item menu-button" exact-active-class="active" to="/help">
|
|
<i class="question circle outline icon"></i>Help
|
|
</router-link>
|
|
</div>
|
|
|
|
<div class="menu-section" v-if="loggedIn" :data-tooltip="`Logout ${this.$store.getters.getUsername}`" data-inverted="" data-position="right center">
|
|
<div v-on:click="destroyLoginToken" class="menu-item menu-button">
|
|
<i v-if="userIcon" class="user outline icon"></i>{{ usernameDisplay }}
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div v-on:click="reloadPage" class="version-display">
|
|
<i :class="`${getVersionIcon()} icon`"></i> {{ version }}
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import axios from 'axios'
|
|
|
|
export default {
|
|
components: {
|
|
'search-input': require('@/components/SearchInput.vue').default,
|
|
'counter':require('@/components/AnimatedCounterComponent.vue').default,
|
|
},
|
|
data: function(){
|
|
return {
|
|
version: '2.2.2',
|
|
username: '',
|
|
collapsed: false,
|
|
mobile: false,
|
|
disableNewNote: false,
|
|
menuOpen: true,
|
|
userIcon: true,
|
|
}
|
|
},
|
|
beforeCreate: function(){
|
|
},
|
|
mounted: function(){
|
|
this.mobile = this.$store.getters.getIsUserOnMobile
|
|
this.collapsed = this.$store.getters.getIsUserOnMobile
|
|
|
|
if(this.mobile){
|
|
this.menuOpen = false
|
|
}
|
|
|
|
if(this.loggedIn){
|
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
|
}
|
|
|
|
},
|
|
computed: {
|
|
loggedIn () {
|
|
//Map logged in from state
|
|
return this.$store.getters.getLoggedIn
|
|
},
|
|
usernameDisplay() {
|
|
|
|
//Remove Emails from username, limit length to 16 chars
|
|
let name = this.$store.getters.getUsername
|
|
let splitName = name.split('@')
|
|
if(splitName.length > 1){
|
|
name = splitName.shift()
|
|
this.userIcon = false
|
|
}
|
|
|
|
if(name.length > 16){
|
|
this.userIcon = false
|
|
}
|
|
|
|
return this.ucWords(name.substring(0, 16))
|
|
},
|
|
},
|
|
methods: {
|
|
menuClicked(){
|
|
//Collapse menu when item is clicked in mobile
|
|
if(this.mobile && !this.collapsed){
|
|
this.collapsed = true
|
|
this.menuOpen = false
|
|
}
|
|
},
|
|
collapseMenu(){
|
|
this.collapsed = !this.collapsed
|
|
|
|
if(!this.collapsed){
|
|
this.menuOpen = true
|
|
} else {
|
|
this.menuOpen = false
|
|
}
|
|
|
|
},
|
|
createNote(event){
|
|
const title = ''
|
|
this.disableNewNote = true
|
|
|
|
axios.post('/api/note/create', {title})
|
|
.then(response => {
|
|
|
|
if(response.data && response.data.id){
|
|
//Redirect to note page if user is not on it
|
|
this.$bus.$emit('open_note', response.data.id)
|
|
this.disableNewNote = false
|
|
}
|
|
})
|
|
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
|
},
|
|
destroyLoginToken() {
|
|
this.$bus.$emit('notification', 'Logged Out')
|
|
this.$store.commit('destroyLoginToken')
|
|
this.$router.push('/')
|
|
},
|
|
toggleNightMode(){
|
|
this.$store.commit('toggleNightMode')
|
|
},
|
|
ucWords(str){
|
|
return (str + '')
|
|
.replace(/^(.)|\s+(.)/g, function ($1) {
|
|
return $1.toUpperCase()
|
|
})
|
|
},
|
|
emitReloadEvent(){
|
|
//Reloads note page to initial state
|
|
this.$bus.$emit('note_reload')
|
|
},
|
|
updateFastFilters(index){
|
|
|
|
//A little hacky, brings user to notes page then filters on click
|
|
if(this.$route.name != 'NotesPage'){
|
|
this.$router.push('/notes')
|
|
setTimeout( () => {
|
|
this.updateFastFilters(index)
|
|
}, 500 )
|
|
}
|
|
|
|
const options = [
|
|
'withLinks', // 'Only Show Notes with Links'
|
|
'withTags', // 'Only Show Notes with Tags'
|
|
'onlyArchived', //'Only Show Archived Notes'
|
|
'onlyShowSharedNotes', //Only show shared notes
|
|
]
|
|
|
|
let filter = {}
|
|
filter[options[index]] = 1
|
|
|
|
this.$bus.$emit('update_fast_filters', filter)
|
|
},
|
|
reloadPage(){
|
|
location.reload(true)
|
|
},
|
|
getVersionIcon(){
|
|
const icons = ['cat','crow','dog','dove','dragon','fish','frog','hippo','horse','kiwi bird','otter','spider', 'smile', 'robot', 'hat wizard', 'microchip', 'atom', 'grin tongue squint', 'radiation']
|
|
const index = ( parseInt(this.version.replace(/\./g,'')) % (icons.length))
|
|
return icons[index]
|
|
|
|
}
|
|
}
|
|
}
|
|
</script> |